Reputation: 9558
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
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
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