3

我正在开发一个新的 MVC 5 项目。它是一个单一的多租户站点,允许许多组织和分支机构维护一个页面。所有页面都以以下 url 格式开头:

http://mysite.com/{organisation}/{branch}/...

例如:

http://mysite.com/contours/albany/...   
http://mysite.com/contours/birkenhead/...   
http://mysite.com/lifestyle/auckland/...   

我在{organisation}and{branch}之前用{controller}and声明了我的 RouteConfig {action}

routes.MapRoute(
    name: "Default",
    url: "{organisation}/{branch}/{controller}/{action}/{id}",
    defaults: new { controller = "TimeTable", 
                    action = "Index", 
                    id = UrlParameter.Optional });

这工作得很好。然而,现在每个控制器的顶部都有相同的代码来检查organisationand branch

public ActionResult Index(string organisation, string branch, string name, int id)
{
    // ensure the organisation and branch are valid
    var branchInst = _branchRepository.GetBranchByUrlPath(organisation, branch);
    if (branchInst == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    // start the real code here...
}

我热衷于 DRY 原则(不要重复自己),我想知道是否有可能以某种方式隔离该公共代码并将我的控制器签名更改为如下所示:

public ActionResult Index(Branch branch, string name, int id)
{
    // start the real code here...
}
4

3 回答 3

3

您可以创建一个通用控制器并让您的其他控制器继承它。例如:

public class YourCommonController : Controller
    {
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var organisation = filterContext.RouteData.Values["organisation"];
            var branch = filterContext.RouteData.Values["branch"];

            // Your validation code here

            base.OnActionExecuting(filterContext);
        }
    }

YourCommonController现在,只需从您想要拥有此共享代码的时间继承即可。

于 2013-10-03T03:06:14.853 回答
1

我必须在应用程序中执行类似的操作,其中用户 ID 和令牌通过 POST 传递给每个控制器操作(因为我们正在执行一些非常古老的遗留身份验证)。

我声明了一个 BaseController 并让每个控制器继承该基本控制器。因此,每个继承基础的控制器都已经可以访问标准的 uid 和令牌属性(如果他们需要的话),并且这些属性已经在每个操作开始时从 HTTP 上下文中检索到。

public abstract class BaseController : Controller
    {
        #region Properties

        protected string uid;
        protected string token;

        #endregion

        #region Event overloads

        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {    
            try
            {
                uid = requestContext.HttpContext.Request["uid"];
                token = requestContext.HttpContext.Request["token"];

                if (uid != null && token != null)
                {
                    ViewBag.uid = uid;

                    if (!token.Contains("%"))
                        ViewBag.token = requestContext.HttpContext.Server.UrlEncode(token);
                    else
                        ViewBag.token = token;

                    base.Initialize(requestContext);
                }
                else
                {
                    requestContext.HttpContext.Response.Redirect(ConfigurationManager.AppSettings.GetValues("rsLocation")[0]);
                }
            }
            // User ID is not in the query string
            catch (Exception ex)
            {
                requestContext.HttpContext.Response.Redirect(ConfigurationManager.AppSettings.GetValues("redirectLocation")[0]);
            }
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

        #endregion
    }

现在您可以在“真实”控制器中继承您的基本控制器。

public class TestController : BaseController
    {
        #region Controller actions

        //
        // GET: /Index/     

        [Authorize]
        public ViewResult Index()
        {
             //blah blah blah
        }
     }

在您的情况下,您将寻找组织和分支而不是 uid 和令牌,但这是相同的想法。

于 2013-10-08T19:19:26.573 回答
0

另一种选择是使用自定义 ActionFilters,这样您就不必记住继承您的基本控制器。AuthorizeAttribute 是一个很好的重载,因为这就是你想要做的。

http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs

 public class ValidationActionFilter : AuthorizeAttribute

 {
      public override void OnAuthorization(AuthorizationContext filterContext)
      {
           var routeData = filterContext.RouteData;
           var branchInst = _branchRepository.GetBranchByUrlPath(routeData.Values["organisation"], routeData.Values["branch"]);
           if (branchInst == null)
           {
              filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.BadRequest);
           }   
      }
 }

在您的 Global.asax 或 FilterConfig 类中,您可以简单地注册它

GlobalFilters.Filters.Add(new ValidationActionFilter());

未经测试的代码,但你明白了..

于 2013-10-03T04:19:47.483 回答