1

我对 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" }
        );
    }

那里一切正常。我们使用默认的 Membership Provider,用户还获得一个 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 测试中。我的数据库有一个视图('Claimed'),它可以返回一个真/假值,具体取决于它所传递的用户配置文件 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 才能让它们工作,他们似乎这样做了(到那时)。我在这里发现了格式:Bind a routevalue to a property作为视图模型一部分的对象

线

var profile = db.Profiles.Where(q => q.ProfileId == id).FirstOrDefault();

数据库上的错误。部分,错误消息如下:

无法通过嵌套类型“MySite.Controllers.HomeController.UserAccountActivatedAttribute”访问外部类型“MySite.Controllers.HomeController”的非静态成员

...这是我努力尝试用 MSDN 和 Stack 来解决的问题,但结果却是空的。这会敲响警钟吗?

4

4 回答 4

3

其他人已经提出了很多建议,但让我在这里提出一些其他的建议。

动作方法选择器

为了保持你的控制器动作干净,你可以编写一个动作方法选择器属性来创建两个简单的动作:

[ActionName("Index")]
public ActionResult IndexNonActivated(int id)
{
    ...
}

[ActionName("Index")]
[UserAccountActivated]
public ActionResult IndexActivated(int id)
{
    ...
}

这样,您就不必在操作中检查代码,从而使它们非常薄。选择器过滤器将确保执行与用户帐户激活状态相关的正确操作。

您可以在我的博客文章中阅读有关操作选择器属性的更多信息,但基本上您必须编写类似于以下内容的内容:

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

两个动作都应该检查状态并相互重定向,以防状态不“适合”。这也意味着每次发生重定向时,都会检查配置文件两次。在每一个动作中。

操作方法选择器将只检查一次配置文件。无论用户配置文件处于什么状态。

于 2012-05-16T07:21:10.120 回答
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) {
  ...  
}
于 2012-05-15T05:41:56.133 回答
0

我建议在控制器中使用该逻辑,因为一旦他/她被激活,他们就可以使用相同的链接访问他们的个人资料。

于 2012-05-15T04:18:06.633 回答
0

检查帐户是否被激活是应用程序逻辑的一部分,应该在控制器内部(或更深层次)实现。在控制器中,您可以将未激活的用户重定向到任何其他控制器/操作以完成激活。URL 路由机制应该简单地根据传入 URL 的形状进行路由,并且不应该联系数据库。

于 2012-05-15T10:30:15.420 回答