我对MVC3相对较新,但我正在使用它,C#和EF4来创建一个应用程序网站。我正在使用的路由与我选择MVC3模式时创建的默认Microsoft项目相同,没什么特别的:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { "MySite.Controllers" }
);
}
那里的一切都很好。我们使用默认的成员资格提供程序,用户还会获得标识其帐户的INT值。这使他们可以通过简单的路由轻松查看他们的个人资料,例如:
www.mysite.com/profile/4
......例如。但是,客户端已要求预先生成许多帐户并将其分发给选定的用户。我已经设法通过SQL Server运行它,它工作正常,所有帐户都创建(大约一千)。此外,我添加了一个位字段('声明'),可以帮助确定这些用户是否已“激活”其中一个预生成的帐户。
我的问题是,当用户获得访问他们(未激活)帐户的链接时,我应该在该页面上执行初始路由时使用测试来识别他们的帐户未提出要求并将其发送到其他地方以完成将详细信息输入其帐户?或者我应该让他们与其他人一起访问同一页面,并在控制器逻辑中添加一些内容,将此记录标识为未声明,然后将其发送到另一个页面以完成输入详细信息等。 ?是否有充分理由做另一个?
那些在他们的Id值中组成(或有印刷错误)的人怎么样,如:
www.mysite.com/profile/40000000000
(到目前为止该网站只有一千个用户),是否应该以类似的方式处理,或者通过不同的方式完全处理? (即,在一种情况下,我们正在识别尚未声明的现有帐户,而在另一种情况下,我们必须确定该帐户甚至不存在。)
非常感谢任何帮助。
修改
我正在尝试实现Soliah建议的解决方案,并且因为if(id!= 0)不喜欢id可能不在INT中这一事实而陷入困境。我现在已经过去了,试图找出一种方法来检查是否有效部分,但可能我还没有解决问题,因为id没有被视为INT?有些事情肯定是不对的,即使我在我的数据库测试有效期间尝试再次转换它。关于我为什么会收到以下错误的任何想法?我错过了什么?
public class ValidProfileIdAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var id = (Convert.ToInt32(filterContext.ActionParameters["Id"]));
if (id != 0)
{
// Check if valid and behave accordingly here.
Profile profile = db.Profiles.Where(q => q.ProfileId == (Convert.ToInt32(id))).FirstOrDefault();
}
base.OnActionExecuting(filterContext);
}
}
Cannot implicitly convert type 'System.Linq.IQueryable<Mysite.Models.Profile>' to 'Mysite.Models.Profile'. An explicit conversion exists (are you missing a cast?)
编辑#2:
我正在研究罗伯特的建议,并取得了部分进展。我的代码目前看起来像这样:
public class UserAccountActivatedAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
bool isActivated = // some code to get this state
return isActivated;
}
}
这是我在阅读博客文章后得到的,并且(不管你信不信)这篇文章:http://pastebin.com/Ea09Gf4B
我需要将ActionSelectorAttribute更改为ActionMethodSelectorAttribute,以便让事情再次发生。
然而,我不知道怎么做是将Id值放入bool isActivated测试中。我的数据库有一个视图('声明'),可以返回一个真/假值,具体取决于用户的配置文件ID,但我没有看到添加ID的位置。会不会像索利亚编辑的那样工作?
if (int.TryParse(filterContext.ActionParameters["Id"], id) && id != 0) {
bool isActivated = db.Claimed.Where(c => c.ProfileId == id).FirstOrDefault();
编辑#3:
这是我目前的代码状态:
public class UserAccountActivatedAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
// get profile id first
int id = int.Parse((string)controllerContext.RouteData.Values["id"]);
var profile = db.Profiles.Where(q => q.ProfileId == id).FirstOrDefault();
bool isActivated = profile;// some code to get this state
return isActivated;
}
}
对我来说,我不得不把事情改为int.Parse((string)controllerContext.RouteData.Values让他们工作,他们似乎做了(到那时)。我发现这里的格式化:{{3 }}
该行
var profile = db.Profiles.Where(q => q.ProfileId == id).FirstOrDefault();
db上的错误。部分,错误消息如下:
无法通过嵌套类型'MySite.Controllers.HomeController.UserAccountActivatedAttribute'
访问外部类型'MySite.Controllers.HomeController'的非静态成员
...这是我努力想用MSDN和Stack弄清楚的东西,只是为了空洞。这会响铃吗?
答案 0 :(得分:3)
其他人已经提出了很多建议,但是让我在这里提出一些其他的建议。
为了保持控制器操作的清洁,您可以编写一个操作方法选择器属性来创建两个简单的操作:
[ActionName("Index")]
public ActionResult IndexNonActivated(int id)
{
...
}
[ActionName("Index")]
[UserAccountActivated]
public ActionResult IndexActivated(int id)
{
...
}
通过这种方式,您无需在操作中检查代码,从而使代码非常精简。选择器筛选器将确保将执行与用户帐户激活状态相关的正确操作。
您可以在my blog post中详细了解操作选择器属性,但基本上您必须编写与此类似的内容:
public class UserAccountActivatedAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
// get profile id first
int id = int.Parse(controllerContext.RouteData.Values["id"] ?? -1);
bool isActivated = // some code to get this state
return isActivated;
}
}
基本上就是这样。
这将使用户无论其帐户是否已被激活,都可以访问其个人资料。或者甚至可能稍后停用......它将在后台无缝工作。
如果您有两个不同名称的操作(如Juraj所示),一个用于活动配置文件,另一个用于激活,则您必须同时进行检查,因为即使是活跃用户也可以访问激活操作:
profile/4 > for active profiles
profile/activate/4 > for inactive profiles
如果状态不适合&#34;则两个动作都应该检查状态并相互重定向。这也意味着每次重定向时,都会检查配置文件两次。在每一个行动中。
操作方法选择器只会检查配置文件一次。无论用户档案是什么状态。
答案 1 :(得分:1)
我更倾向于保持我的控制器很薄,并将其置于动作过滤器中,您可以在Index
控制器的Profile
操作上进行注释。
public class ValidProfileIdAttribute : ActionFilterAttribute {
public override void OnActionExecuting(ActinExecutingContext filterContext) {
int id;
if (int.TryParse(filterContext.ActionParameters["Id"], id) && id != 0) {
// Check if valid and behave accordingly here.
var profile = db.Profiles.Where(q => q.ProfileId == id).FirstOrDefault();
}
base.OnActionExecuting(filterContext);
}
}
在控制器执行操作之前,将调用OnActionExecuting
方法。
在您的控制器中:
[ValidProfileId]
public ActionResult Index(int id) {
...
}
答案 2 :(得分:0)
我建议在控制器中使用该逻辑,因为一旦他/她被激活,他们就可以使用相同的链接来访问他们的个人资料。
答案 3 :(得分:0)
检查帐户是否被激活是应用程序逻辑的一部分,应该在控制器内部(或更深层次)实现。在控制器中,您可以将未激活的用户重定向到任何其他控制器/操作以完成激活。 URL路由机制应该根据传入URL的形状进行路由,并且不应该与数据库联系。