shytikov
shytikov

Reputation: 9558

Get attributes for method given by name in ASP.NET MVC 4

I'm using ravendb as storage backend. Since it uses unit of work pattern I need to open session, perform actions, save results and close session. I want to keep my code clean and don't call session opening and closing explicitly in each action, so I put this code to OnActionExecuting and OnActionExecuted methods, like this:

    #region RavenDB's specifics

    public IDocumentSession DocumentSession { get; set; }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.IsChildAction)
        {
            return;
        }

        this.DocumentSession = Storage.Instance.OpenSession();
        base.OnActionExecuting(filterContext);
    }

    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.IsChildAction)
        {
            return;
        }

        if (this.DocumentSession != null && filterContext.Exception == null)
        {
            this.DocumentSession.SaveChanges();
        }

        this.DocumentSession.Dispose();
        base.OnActionExecuted(filterContext);
    }

    #endregion

But some actions require connection to ravendb and come don't. So I've decided to create custom attribute and mark methods need to have DocumentSession opened with it. Here is an example:

    //
    // GET: /Create

    [DataAccess]
    public ActionResult Create()
    {
        return View();
    }

And I stuck. My plan was to retrieve actions' attributes in the OnActionExecuted method and if [DataAccess] is present, open DocumentSession.

In the OnActionExecuted I can retrieve action name (method's name) via filterContext.ActionDescriptor.ActionName statement. But how I can retrieve method's attributes of the given class using reflection?

I found out that it might be Attribute.GetCustomAttributes call, but closest I got — I need to have MemberInfo object of the method. But how I can get this MemberInfo for method given by name?

Upvotes: 2

Views: 788

Answers (2)

Kirill Bestemyanov
Kirill Bestemyanov

Reputation: 11964

If you inherit your custom attribute from FilterAttribute, it will have OnActionExecuted and OnActionExecuting methods. And it will be executed before general OnActionExecuted and OnActionExecuting.

Example:

public class DataAccessAttribute: FilterAttribute, IActionFilter
{       

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.IsChildAction)
        {
            return;
        }
        var controller = (YourControllerType)filterContext.Controller;
        controller.DocumentSession = Storage.Instance.OpenSession();
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.IsChildAction)
        {
            return;
        }
        var controller = (YourControllerType)filterContext.Controller;
        documentSession = controller.DocumentSession; 
        if (documentSession != null && filterContext.Exception == null)
        {
            documentSession.SaveChanges();
        }

        documentSession.Dispose();
}

Upvotes: 4

Betty
Betty

Reputation: 9189

Why not have your DataAccess attribute inherit from ActionFilterAttribute so you can put the ActionExecuting/Executed methods on the attribute instead of the Controller?

Example of how to do it with NHibernate by using an action filter to set the session on a base controller. It's done using NHibernate, but very similar to what you'd need to do and it's written by Ayende who's one of the RavenDB authors I believe.

Upvotes: 1

Related Questions