MVC3使用路由或使用控制器逻辑? [英] MVC3 using routes or using controller logic?

查看:223
本文介绍了MVC3使用路由或使用控制器逻辑?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我比较新的MVC3,但我正在使用它,C#和EF4创建一个应用程序网站。我使用的路由与我选择MVC3模式时创建的默认Microsoft项目相同,没有什么特别的:

  public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute({resource} .axd / {* pathInfo});

routes.MapRoute(
Default,//路由名称
{controller} / {action} / {id},//带参数的URL
new {controller =Home,action =Index,id = UrlParameter.Optional},//参数defaults
new [] {MySite.Controllers}
);
}

一切都正常工作。我们使用默认的会员资格提供者,用户也可以获得一个识别他们帐户的INT值。这让他们可以轻松地看到他们的个人资料,只需一个简单的路线:



www.mysite.com/profile/4



...例如。然而,客户端已经要求大量帐户被预先生成并分发给选定的用户。我已经通过SQL Server处理了一种方法来运行,它的工作正常,所有的帐户被创建(大约一千)。此外,我添加了一个有用的字段(Claimed),可以帮助您确定这些预生成的帐户之一是否已被这些用户激活。



我的问题是,当用户被给予一个链接来访问他们的(未激活的)帐户时,我应该在该页面上执行初始路由选择时进行测试,以将其帐户标识为未声明并将其发送到其他地方,以完成在其帐户中输入详细信息?或者我应该让他们与其他人一样去页面,并且在控制器逻辑中有一些将该记录标识为未声明的逻辑,然后将它们发送到另一个页面以完成输入详细信息等。 ?有没有一个很好的理由呢?



在Id值中组成(或排版错误)的人如何: p>

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)
{
//检查是否有效,并在此处执行相应操作。
Profile profile = db.Profiles.Where(q => q.ProfileId ==(Convert.ToInt32(id)))。FirstOrDefault();
}
base.OnActionExecuting(filterContext);
}
}


不能将类型System.Linq.IQueryable< Mysite.Models.Profile>隐式转换为Mysite.Models.Profile。存在一个明确的转换(你错过了一个演员?)

编辑#2: strong>



我正在研究罗伯特的建议,并取得了部分进展。我的代码目前看起来像这样:

  public class UserAccountActivatedAttribute:ActionMethodSelectorAttribute 
{
public override bool IsValidForRequest ControllerContext controllerContext,System.Reflection.MethodInfo methodInfo)
{
if(controllerContext == null)
{
throw new ArgumentNullException(controllerContext);
}
bool isActivated = //某些代码获取此状态
返回isActivated;
}
}

阅读博客条目后, (相信或不相信)这个帖子: http://pastebin.com/Ea09Gf4B



我需要将ActionSelectorAttribute更改为ActionMethodSelectorAttribute才能使事情再次移动。



但是,我看不到如何做是将Id值转换成bool isActivated测试。我的数据库有一个视图('Claimed'),它可以返回一个true / false值,具体取决于用户的配置文件ID,但我看不到添加Id的位置。有什么像Soliah编辑的工作吗?

  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) ;
}
//获取配置文件id首先
int id = int.Parse((string)controllerContext.RouteData.Values [id]);
var profile = db.Profiles.Where(q => q.ProfileId == id).FirstOrDefault();
bool isActivated = profile; //某些代码获取此状态
返回isActivated;
}
}

对我来说,我不得不将事情改为int。解析(())controllerContext.RouteData.Values让它们工作,他们似乎在做(到那时)我发现格式在这里:将路由值绑定到属于viewmodel的对象的属性



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

错误消息如下:


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


...这是我用MSDN和Stack努力找出的东西,只是想空出来。其他人已经提出了许多事情,但是让我把这些东西带到这里。 / p>

操作方法选择器



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

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

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

处理检查您的行动中的代码,使他们真的很薄。选择器过滤器将确保执行与用户帐户激活状态相关的正确操作。



您可以在我的博文,但基本上你必须写一些类似的内容: / p>

  public class UserAccountActivatedAttribute:ActionMethodSelectorAttribute 
{
public override bool IsValidForRequest(ControllerContext controllerContext,MethodInfo methodInfo)
{
if(controllerContext == null)
{
throw new ArgumentNullException(controllerContext);
}

//获取配置文件id首先
int id = int.Parse(controllerContext.RouteData.Values [id] ?? -1);

bool isActivated = //某些代码获取此状态

return isActivated;
}
}

基本上是这样。



这将使用户无论他们的帐户是否被激活,都可以访问他们的个人资料。或者甚至可以在稍后的时间停用...它将在后台无缝工作。



一个重要优点



如果您有两个不同名称的操作(如Juraj建议),一个用于活动配置文件,另一个用于激活,则必须同时进行检查,因为即使活动用户也可以访问激活操作:

 个人资料/ 4>对于活动配置文件
profile / activate / 4>对于不活动的配置文件

两个操作都应该检查状态并重定向到对方,如果状态不适合。这也意味着每次重定向都会发生,配置文件将被检查两次。在每个动作中。



动作方法选择器只会检查一次一次。无论用户的状态是什么状态。


I'm relatively new with MVC3, but I'm using it, C# and EF4 to create an application website. The routing that I'm using is the same as in the default Microsoft project created when I selected MVC3 pattern, nothing special:

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

And everything is working fine there. We're using the default Membership Provider, and users also get an INT value that identifies their account. This lets them see their profile pretty easily with a simple routing like:

www.mysite.com/profile/4

...for example. However, the client has asked that a lot of accounts be pre-generated and distributed to selected users. I've worked up a way to run that through SQL Server and it works fine, all the accounts got created (about a thousand). Additionally, I've add a bit field ('Claimed') that can help identify whether one of these pre-generated accounts has been 'activated' by these users.

My question is, when a user is given a link to come visit their (un-activated) account, should I use a test when doing the initial routing on that page to identify their account as un-claimed and send them somewhere else to finish entering details into their account? Or should I let them go to the same page as everyone else, and have something in the controller logic that identifies this record as un-claimed, and then send them to another page to finish entering details etc.? Is there a good reason for doing one over the other?

And what about people who make up (or have a typographical error) in their Id value, like:

www.mysite.com/profile/40000000000

(and the site only has a thousand users so far), should that be handled similarly, or through different means entirely? (I.e., in one scenario we're identifying an existing account that is not yet claimed, and in another scenario we're having to figure out that the account doesn't even exist.)

Any help would be greatly appreciated.

EDIT:

I'm trying to implement Soliah's suggested solution, and got stuck a bit on the fact that the if (id != 0) didn't like that the id might not be in an INT. I'm past that now, and attempting to figure out a way to do the check if valid portion, but possibly I have not solved the problem with the id not being treated as an INT? Something is definitely not right, even though I'm trying to convert it again during my database test for validity. Any ideas on why I'm getting the error below? What am I missing?

    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?)

EDIT #2:

I'm working on Robert's suggestion, and have made partial progress. My code currently looks like this:

    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;
        }
    }

which I got to after reading the blog entry, and (believe it or not) this posting: http://pastebin.com/Ea09Gf4B

I needed to change ActionSelectorAttribute to ActionMethodSelectorAttribute in order to get things moving again.

However, what I don't see how to do is to get the Id value into the bool isActivated test. My database has a view ('Claimed') which can give back a true/false value, depending on the user's profile Id that it is handed, but I don't see where to add the Id. Would something like what Soliah edited work?

if (int.TryParse(filterContext.ActionParameters["Id"], id) && id != 0) {

    bool isActivated = db.Claimed.Where(c => c.ProfileId == id).FirstOrDefault();

EDIT #3:

Here is my current state of the code:

    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;
        }
    }

For me, I had to change things to int.Parse((string)controllerContext.RouteData.Values to get them to work, which they seem to do (to that point.) I discovered that formatting here: Bind a routevalue to a property of an object that is part of viewmodel

The line

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

errors on the db. section, with error message as follows:

Cannot access a non-static member of outer type 'MySite.Controllers.HomeController' via nested type 'MySite.Controllers.HomeController.UserAccountActivatedAttribute'

...which is something that I have diligently tried to figure out with MSDN and Stack, only to come up empty. Does this ring any bells?

解决方案

Others have suggested many things already, but let me bring something else to the table here.

Action Method Selector

In order to keep your controller actions clean, you can write an action method selector attribute to create two simple actions:

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

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

This way you don't deal with checking code in your actions keeping them really thin. Selector filter will make sure that correct action will get executed related to user account activation state.

You can read more about action selector attributes in my blog post but basically you'd have to write something similar to this:

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;
    }
}

And that's basically it.

This will make it possible for users to access their profile regardless whether their account has been activated or not. Or maybe even deactivated at some later time... And it will work seamlessly in the background.

One important advantage

If you'd have two actions with different names (as Juraj suggests), one for active profiles and other for activation, you'd have to do the checking in both, because even active users would be able to access activation action:

profile/4 > for active profiles
profile/activate/4 > for inactive profiles

Both actions should be checking state and redirect to each other in case that state doesn't "fit". This also means that each time a redirection would occur, profile will get checked twice. In each action.

Action method selector will check profiles only once. No matter what state user profile is in.

这篇关于MVC3使用路由或使用控制器逻辑?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆