尝试在页面加载时将2个异步ajax请求转换为具有相同IActionFilter属性的2个MVC操作时出现并发问题。
SimpleInjector注册如下
Product.find(req.params.isbn, function(err, product){
if(!product) res.status(404).send({message: 'Product not exits'});
console.log("PUT - /products/" + req.params.isbn);
product.isbn = req.body.isbn;
product.title = req.body.title;
product.author = req.body.author;
product.active = req.body.active;
product.template = req.body.template;
let updateproduct = new Product(product);
updateproduct.save(function(err){
if(err) return res.send(500,err.message);
console.log("Successfully updated: " + req.body.isbn);
res.status(200).json(product);
});
});
};
以下是同步ActionFilter的2个动作
public static Container Initialize(IAppBuilder app)
{
var container = GetInitializeContainer(app);
RegisterGlobalFilters(GlobalFilters.Filters, container);
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
return container;
}
private static Container GetInitializeContainer(IAppBuilder app)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.RegisterSingleton(app);
RegisterCustomDependacies(container);
container.Register(() => new ApplicationDbContext(), Lifestyle.Scoped);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
//At the moment of verification, there is now HttpContext to check. So create a new owin context to check instead and get the authentication manager.
container.Register(() => AdvancedExtensions.IsVerifying(container) ? new OwinContext(new Dictionary<string, object>()).Authentication
: HttpContext.Current.GetOwinContext().Authentication, Lifestyle.Scoped);
return container;
}
public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
//Originally had this but it was causing the same issues
//filters.Add(new AuthoriseActionFilter(container.GetInstance<ICacheManager>(),
// container.GetInstance<IUserManager>(),
// container.GetInstance<IAuthorisationManager>(),
// container.GetInstance<IClientManager>(),
// container.GetInstance<ICookieManager>(),
// container.GetInstance<IAuthenticator>()
// ));
container.Register<IActionFilter, AuthoriseActionFilter>(Lifestyle.Scoped);
filters.Add(container.GetInstance<IActionFilter>());
filters.Add(new HandleErrorAttribute());
}
当ActionFilter从数据库请求某些信息时,会出现此问题。我收到以下错误。
已经有一个与此Connection关联的打开DataReader,必须先关闭它。
每4页刷新一次只会发生一次。
以下是我的IActionFilter的简化版本
[AuthoriseAction("Can_Access_Summary")]
public async Task<PartialViewResult> ReturnPots(int? dateID, string date) {}
[AuthoriseAction("Can_Access_Summary")]
public async Task<string> GetImportedDates() {}
我可以通过使我的一个ajax请求同步来解决这个问题,但这不是一个真正的解决方案。我也可以通过1个请求返回所有数据,但同样,它不是真正正确的解决方案。
由于
答案 0 :(得分:1)
You can solve this problem with a simple extension method:
internal static class SimpleInjectorMvcActionFilterExtensions
{
public static void AddFilter<TActionFilter>(
this GlobalFilterCollection filters, Container container)
where TActionFilter : class, IActionFilter
{
// Register instance in the container to allow this instance to be
// diagnosed.
container.Register<TActionFilter>(Lifestyle.Scoped);
// Add a proxy to the global filters that resolves the real instance
filters.Add(new ActionFilterProxy<TActionFilter>(container));
}
private sealed class ActionFilterProxy<TActionFilter> : IActionFilter
where TActionFilter : class, IActionFilter
{
private readonly Container container;
public ActionFilterProxy(Container container) { this.container = container; }
public void OnActionExecuting(ActionExecutingContext c)=> Get().OnActionExecuting(c);
public void OnActionExecuted(ActionExecutedContext c)=> Get().OnActionExecuted(c);
private TActionFilter Get() => container.GetInstance<TActionFilter>();
}
}
You can use this as follows:
public static void RegisterGlobalFilters(
GlobalFilterCollection filters, Container container)
{
// Call extension method
filters.AddFilter<AuthoriseActionFilter>(container);
filters.Add(new HandleErrorAttribute());
}
Instead of adding the AuthoriseActionFilter
to the list of global filters (a list of singletons), an instance of ActionFilterProxy<AuthoriseActionFilter>
is added. This proxy instance can safely be used as singleton, because it will call back into the container
on each request and resolve a new AuthoriseActionFilter
for each request.