2

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?

2 Answers 2

4

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();
}
Sign up to request clarification or add additional context in comments.

5 Comments

Hm... DocumentSession should belong to controller instance. Otherwise I would able to save and retrieve data. Or I need to come up with the way how to perform this.
You have instance of ControllerBase Controller in filterContext. You can cast it to type of your controller and take any property of it. I update my answer.
Thanks, it sounds like answer I've searching for!
One small thing: calls to base are illegal in this case.
Tested. Works fine! Thank you Kirill!
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.