有没有办法将DbContext的实例从控制器传递给ActionFilter?

时间:2017-08-31 21:21:06

标签: c# asp.net-mvc asp.net-mvc-5 actionfilterattribute custom-action-filter

我有一个在ASP.NET MVC 5框架顶部使用c#编写的应用程序。

我通过继承ValidateCookieValueAction类创建了自定义操作过滤器(即ActionFilterAttribute)。我对我的多个操作方法使用ValidateCookieValueAction属性。

过滤器的目的是确保用户在允许其进入操作之前具有cookie值。尽管存在安全问题,但过滤器效果很好。但是,在让用户进入之前,需要验证cookie值本身。

要验证cookie值,我需要一个DbContext的实例,这样我就可以查询数据库并验证cookie值。

我知道我可以直接在ActionFilter中创建DbContext的新实例。但是,我想要狂热。我希望能够从控制器传递我已创建的DbContext实例,以允许我重用已在控制器中建立的连接。

以下是我的控制器设置方法

public class BaseController 
{
    protected IDbContext Context { get; private set; }

    protected override void Initialize(RequestContext requestContext)
    {
        base.Initialize(requestContext);

        Context = new DbContext();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            Context.Dispose();
        }

        base.Dispose(disposing);
    }
}

public class TestController : BaseController 
{
    [ValidateCookieValueAction]
    public ActionResult Index()
    {
        // the uses is in!
        return View();
    }
}

这是我的动作过滤器类

public class ValidateCookieValueAction : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        var cookie = new CookieJar(filterContext.HttpContext);
        if (!cookie.Has(ContactListCookieName))
        {
            var Url = new UrlHelper(filterContext.RequestContext);
            var url = Url.Action("Guest", "Test");

            filterContext.Result = new RedirectResult(url);
        }
    }
}

如何将Context的实例传递给ValidateCookieValueAction

2 个答案:

答案 0 :(得分:1)

这与原始问题没有直接关系,但您似乎自己创建了身份验证机制。如果没有,请告诉我;我只是删除了这个答案。

ASP.NET已经有 ASP.NET标识 ,它比我们自己创建它更安全,更可靠。但是,如果要使用现有的自定义表,则可以使用基本上是ASP.NET标识子集的OWIN中间件。

使用OWIN中间件的主要优点是您可以使用ASP.NET MVC附带的 授权 属性。实施比您想象的要容易得多。

示例代码 -

OWIN Authentication Middle-ware

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "ApplicationCookie",
            LoginPath = new PathString("/Account/Login")
        });
    }
}

Store access as role claim in Principle object

public void SignIn(User user, IList<string> roleNames)
{
    IList<Claim> claims = new List<Claim>
    {
        new Claim(ClaimTypes.Sid, user.Id.ToString()),
        new Claim(ClaimTypes.Name, user.UserName),
        new Claim(ClaimTypes.GivenName, user.FirstName),
        new Claim(ClaimTypes.Surname, user.LastName),
    };

    foreach (string roleName in roleNames)
    {
        claims.Add(new Claim(ClaimTypes.Role, roleName));
    }

    ClaimsIdentity identity = new ClaimsIdentity(claims, AuthenticationType);

    IOwinContext context = _context.Request.GetOwinContext();
    IAuthenticationManager authenticationManager = context.Authentication;

    authenticationManager.SignIn(identity);
}

用法

[Authorize(Roles = "CanViewHome")]
public class IndexController : Controller
{
    [Authorize(Roles = "CanEditHome")]
    public ActionResult Edit()
    {
        return View();
    }
}

答案 1 :(得分:0)

默认情况下,当前上下文中已存在上下文。

在Startup.Configuration(IAppBuilder应用程序)

app.CreatePerOwinContext(ApplicationDbContext.Create); // this already stores a DbContext

您可以使用

获取它
var dbContext = HttpContext.GetOwinContext().Get<ApplicationDbContext>();

或者,您可以将Context存储在[TempData]或[Session]中。
如果你在同一个Request中重新获取它,那么只需在Context.Items []中抛出DbContext,这些只是当前Request的最后一个。

OnActionExecuting中的

filterContext.Controller.TempData
控制器中的

this.TempData