我正在使用structuremap在asp.net mvc custom acitonfilte中遇到问题 在我的" LogAttribute" class i有setter依赖注入,当执行" OnActionExecuted"我的customfilterclass的方法是" LogAttribute"
我的LogAttribute类代码是
public class LogAttribute : ActionFilterAttribute
{
public ApplicationDbContext Context { get; set; }
public string Description { get; set; }
public LogAttribute(string description)
{
Description = description;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var userId = filterContext.HttpContext.User.Identity.GetUserId();
var user = Context.Users.Find(userId); **i am getting error here the Context is coming null here**
Context.Logs.Add(new Log(user, filterContext.ActionDescriptor.ActionName,
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
Description
)
);
Context.SaveChanges();
}
}
我创建了另一个类,我将值传递给setter依赖属性
public class StructureMapFilterProvider : FilterAttributeFilterProvider
{
private readonly Func<IContainer> _container;
public StructureMapFilterProvider(Func<IContainer> container)
{
_container = container;
}
public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(controllerContext, actionDescriptor);
var container = _container();
foreach (var filter in filters)
{
container.BuildUp(filter.Instance);
yield return filter;
}
}
}
我的依赖解析器类代码是
public class StructureMapDependencyResolver : IDependencyResolver
{
private readonly Func<IContainer> _containerFactory;
public StructureMapDependencyResolver(Func<IContainer> containerFactory)
{
_containerFactory = containerFactory;
}
public object GetService(Type serviceType)
{
if (serviceType == null)
{
return null;
}
var container = _containerFactory();
return serviceType.IsAbstract || serviceType.IsInterface
? container.TryGetInstance(serviceType)
: container.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _containerFactory().GetAllInstances(serviceType).Cast<object>();
}
}
我的global.ascx代码是
public class MvcApplication : System.Web.HttpApplication
{
public IContainer Container
{
get
{
return (IContainer)HttpContext.Current.Items["_Container"];
}
set
{
HttpContext.Current.Items["_Container"] = value;
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DependencyResolver.SetResolver(new StructureMapDependencyResolver(() => Container ?? ObjectFactory.Container));
ObjectFactory.Configure(cfg =>
{
cfg.Scan(Scan =>
{
Scan.TheCallingAssembly();
Scan.WithDefaultConventions();
Scan.With(new ControllerConfiguration());
});
cfg.For<IFilterProvider>().Use(new StructureMapFilterProvider(() => Container ?? ObjectFactory.Container));
cfg.For<IUserStore<ApplicationUser>>()
.Use<UserStore<ApplicationUser>>();
cfg.For<DbContext>()
.Use(() => new ApplicationDbContext());
cfg.SetAllProperties(x =>
x.Matching(p =>
p.DeclaringType.CanBeCastTo(typeof(ActionFilterAttribute)) &&
p.DeclaringType.Namespace.StartsWith("TestingSturctureMap") &&
p.PropertyType.IsPrimitive &&
p.PropertyType != typeof(string)));
});
}
public void Application_BeginRequest()
{
Container = ObjectFactory.Container.GetNestedContainer();
}
public void Application_EndRequest()
{
Container.Dispose();
Container = null;
}
}
答案 0 :(得分:6)
我安装了structuremap
和StructureMap.MVC5
NuGet套餐
这已添加DependencyResolution
文件夹和StructuremapMvc.cs
到App_Start
文件夹
然后,我创建了Filters
文件夹,并向其添加了属性,操作过滤器和过滤器提供程序类:
我的属性类 - LogActionsAttribute
- 是最简单的。
它只是一个没有引用任何操作的属性:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class LogActionsAttribute : System.Attribute
{
}
Controller
上的用法:
[LogActions]
public class HomeController : System.Web.Mvc.Controller
{
public ActionResult Index()
{
return View();
}
}
现在我需要添加一个动作过滤器来查找此属性并执行某些操作。在我的例子中,记录传入的参数和执行结果。 ILog
是一个自定义界面,包含此过滤器使用的这两种方法。
ControllerLoggerFilter
上课:
public class ControllerLoggerFilter : IActionFilter
{
private readonly ILog _log;
private string _request;
public ControllerLoggerFilter(ILog log)
{
_log = log;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (ApplyBehavior(filterContext))
{
ActionExecuting(filterContext);
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
if (ApplyBehavior(filterContext))
{
ActionExecuted(filterContext);
}
}
private void ActionExecuting(ControllerContext c)
{
if (c == null || c.HttpContext == null)
return;
_log.LogInput(c.HttpContext.Request);
_request = c.HttpContext.Request;
}
private void ActionExecuted(ControllerContext c)
{
if (c.HttpContext.Response == null)
return;
_log.LogOutput(_request, c.HttpContext.Response);
}
private static bool ApplyBehavior(ActionExecutingContext filterContext)
{
return
filterContext.ActionDescriptor.ControllerDescriptor
.GetCustomAttributes(typeof (LogActionsAttribute),
false).Any();
}
private static bool ApplyBehavior(ActionExecutedContext filterContext)
{
return
filterContext.ActionDescriptor.ControllerDescriptor
.GetCustomAttributes(typeof (LogActionsAttribute),
false).Any();
}
}
我现在不得不告诉MVC这个过滤器需要在管道中。由于它是由structuremap容器构建的,因此我需要一个自定义IFilterProvider
:
public class MvcInjectableFilterProvider : IFilterProvider
{
private readonly IEnumerable<Filter> _list;
public MvcInjectableFilterProvider(IContainer container)
{
_list = GetContainerFilters(container);
}
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
return _list;
}
private static IEnumerable<Filter> GetContainerFilters(IContainer container)
{
return
container.GetAllInstances<IActionFilter>()
.Select(instance => new Filter(instance, FilterScope.Action, null));
}
}
最后要做的事情:在我的IoC.cs
中注册我的课程
这是我在安装NuGet软件包时创建的文件中唯一需要修改的地方。
public static class IoC {
public static IContainer Initialize() {
return new Container(c =>
{
c.AddRegistry<DefaultRegistry>();
// added these lines:
c.For<ILog>().Use<Log>();
c.For<IActionFilter>().Use<ControllerLoggerFilter>();
c.For<IFilterProvider>().Use<MvcInjectableFilterProvider>();
});
}
}
来源:
Mark Seemann(以及其他所有地方)
Javier G. Lozano
eric.sowell
K. Scott Allen
答案 1 :(得分:1)
亲爱的朋友们,我解决了我的问题,我的LogAttribute类中的setter属性只缺少[SetterProperty]
public class LogAttribute : ActionFilterAttribute
{
[SetterProperty]
public ApplicationDbContext Context { get; set; }
public string Description { get; set; }
public LogAttribute(string description)
{
Description = description;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var userId = filterContext.HttpContext.User.Identity.GetUserId();
var user = Context.Users.Find(userId);
Context.Logs.Add(new Log(user, filterContext.ActionDescriptor.ActionName,
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
Description
)
);
Context.SaveChanges();
}
}
现在正在工作:)
答案 2 :(得分:0)
在ActionFilters中拥有setter属性非常糟糕! 可以在多个请求之间共享相同的actionFilter实例。结果,不同的请求(线程)将获得对ApplicationDbContext的相同引用。
Are ActionFilterAttributes reused across threads? How does that work?