c# - DbContext.Set 和其他地方的实体框架 ASP.NET MVC(有时)问题
问题描述
将 ASP.NET 与 Entity Framework 和 Unity Container 结合使用时,我遇到了一个奇怪的问题。
此问题仅在应用程序运行几小时到几天后才会出现。发生这种情况后,它会通过重新启动 IIS 暂时修复(同样在同一时期)。
有时问题会在尝试注入(使用统一容器)控制器时出现异常。
例子:
public class PersonController
{
private readonly ICrudService<Person> personCrudservice;
public PersonController(ICrudService<Person> personCrudservice)
{
this.personCrudservice = personCrudservice;
}
}
这里的例外是:An error occurred when trying to create a controller of type 'PersonController'. Make sure that the controller has a parameterless public constructor.
当然控制器没有无参数构造函数,但是使用统一容器注入 personCrudservice。但是,这不会发生,因为该dbContext.Set<Person>()
方法给出了以下异常:An item with the same key has already been added.
这会导致上面显示的异常。
另一个示例是尝试从数据库加载数据时的异常。这给出了 NullReference 异常。(同样,并非所有时间和数据都存在于数据库中)
你们能帮我解决这个问题吗?
数据上下文.cs:
public class DataContext : IUnitOfWork, IRepositoryFactory, ICrudServiceFactory
{
private const string CONNECTIONSTRING = "Constring";
private static readonly MedicijnverstrekkingDbContext dbContext = new MedicijnverstrekkingDbContext(CONNECTIONSTRING);
public DbContext DbContext => dbContext;
public static volatile Dictionary<string, object> repositories = new Dictionary<string, object>();
public DataContext()
{
dbContext.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
}
public void SaveChanges()
{
dbContext.SaveChanges();
}
public void Dispose()
{
dbContext.Dispose();
}
public IRepository<T> CreateRepositoryFor<T>() where T : class, IEntity
{
var naam = typeof(T).FullName;
var repos = default(IRepository<T>);
if(repositories.ContainsKey(naam))
{
repos = repositories[naam] as IRepository<T>;
}
if(repos == null)
{
repos = new Repository<T>(dbContext.Set<T>());
repositories[naam] = repos;
}
return repos;
}
ICrudService<T> ICrudServiceFactory.GenerateCrudServiceFor<T>(IUnityContainer unityContainer)
{
var icrudServiceType = typeof(ICrudService<T>);
var tService = icrudServiceType.Assembly.GetTypes().Where(t => icrudServiceType.IsAssignableFrom(t)).FirstOrDefault();
//If predefined crud service exists, create an instance, otherwise create a generic crud service.
if (tService != null)
{
return (ICrudService<T>)Activator.CreateInstance(tService, new object[] { unityContainer.Resolve<IUnitOfWork>(), unityContainer.Resolve<IRepository<T>>() });
}
else
{
return new GenericCrudService<T>(unityContainer.Resolve<IUnitOfWork>(), unityContainer.Resolve<IRepository<T>>());
}
}
}
UnityConfig.cs
public class UnityConfig
{
private static readonly Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer Container => container.Value;
public static void RegisterTypes(IUnityContainer container)
{
RegisterDependencies(container);
System.Web.Mvc.DependencyResolver.SetResolver(new UnityDependencyResolverAdapter(container));
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
private static void RegisterDependencies(IUnityContainer unityContainer)
{
RegisterDataContextAndUnitOfWork(unityContainer);
RegisterRepositories(unityContainer);
RegisterAuthenticationDependencies(unityContainer);
}
private static void RegisterDataContextAndUnitOfWork(IUnityContainer container)
{
container.RegisterType<IUnitOfWork, DataContext>(HttpContextLifetimeManager.FromType<DataContext>());
container.RegisterType<IRepositoryFactory, DataContext>(HttpContextLifetimeManager.FromType<DataContext>());
container.RegisterType<ICrudServiceFactory, DataContext>(HttpContextLifetimeManager.FromType<DataContext>());
}
private static void RegisterAuthenticationDependencies(IUnityContainer container)
{
container.RegisterType<IUserStore<GebruikerModel>, UserStore>(HttpContextLifetimeManager.FromType<UserStore>());
container.RegisterType<IRoleStore<RoleModel, string>, RoleStore>(HttpContextLifetimeManager.FromType<RoleStore>());
container.RegisterFactory<UserManager<GebruikerModel>>(unityContainer =>
{
var userStore = unityContainer.Resolve<IUserStore<GebruikerModel>>();
var manager = new UserManager<GebruikerModel>(userStore)
{
PasswordHasher = new BcryptPasswordHasher()
};
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<GebruikerModel>
{
MessageFormat = "Uw inlogcode is {0}."
});
manager.SmsService = new SmsService();
return manager;
});
container.RegisterType<ICurrentUserProvider, CurrentHttpUserProvider>();
}
private static void RegisterRepositories(IUnityContainer container)
{
var registerRepositoryMethodName = MemberNameHelper.GetActionName(() => RegisterRepository<IEntity>(container));
var registerCrudserviceName = MemberNameHelper.GetActionName(() => RegisterCrudService<IEntity>(container));
var registerRepositoryMethodInfo = typeof(UnityConfig).GetMethod(registerRepositoryMethodName, BindingFlags.NonPublic | BindingFlags.Static);
var registerCrudserviceMethodInfo = typeof(UnityConfig).GetMethod(registerCrudserviceName, BindingFlags.NonPublic | BindingFlags.Static);
foreach (var entityType in typeof(IEntity).Assembly.GetTypes().Where(t => typeof(IEntity).IsAssignableFrom(t)))
{
var registerRepositoryMethod = registerRepositoryMethodInfo.MakeGenericMethod(entityType);
registerRepositoryMethod.Invoke(null, new object[] { container });
var registerCrudserviceMethod = registerCrudserviceMethodInfo.MakeGenericMethod(entityType);
registerCrudserviceMethod.Invoke(null, new object[] { container });
}
}
private static void RegisterRepository<T>(IUnityContainer unityContainer) where T : class, IEntity
{
unityContainer.RegisterFactory<IRepository<T>>(
factory => factory.Resolve<IRepositoryFactory>().CreateRepositoryFor<T>(),
HttpContextFactoryLifetimeManager.ForRepository<T>()
);
}
private static void RegisterCrudService<T>(IUnityContainer unityContainer) where T : class, IEntity
{
unityContainer.RegisterFactory<ICrudService<T>>(
factory => factory.Resolve<ICrudServiceFactory>().GenerateCrudServiceFor<T>(factory),
HttpContextFactoryLifetimeManager.ForCrudService<T>()
);
}
}
我已经有这个问题好几个星期了,尝试不同的 LifeTimeManagers 并且降级 Unity-Container / Entity Framework 也没有帮助。
Stacktrace:已添加具有相同密钥的项目。
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Data.Entity.Internal.InternalContext.Set[TEntity]()
at System.Data.Entity.DbContext.Set[TEntity]()
at Multitask.COMPANYNAME.DataAccess.EntityFramework.DataContext.CreateRepositoryFor[T]() in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\DataAccess\DataContext.cs:line 50
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Multitask.COMPANYNAME.WebApplication.Unity.HttpContextFactoryLifetimeManager.GetValue(ILifetimeContainer container) in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\WebApplication\Unity\HttpContextFactoryLifetimeManager.cs:line 60
at Unity.Strategies.LifetimeStrategy.PreBuildUp(BuilderContext& context)
at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)
at Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)
at Unity.UnityContainerExtensions.Resolve[T](IUnityContainer container, ResolverOverride[] overrides)
at Multitask.COMPANYNAME.DataAccess.EntityFramework.DataContext.Multitask.COMPANYNAME.Service.DataAccess.ICrudServiceFactory.GenerateCrudServiceFor[T](IUnityContainer unityContainer) in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\DataAccess\DataContext.cs:line 131
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Multitask.COMPANYNAME.WebApplication.Unity.HttpContextFactoryLifetimeManager.GetValue(ILifetimeContainer container) in C:\Source\Workspaces\Multitask.COMPANYNAME\Multitask.COMPANYNAME\WebApplication\Unity\HttpContextFactoryLifetimeManager.cs:line 70
at Unity.Strategies.LifetimeStrategy.PreBuildUp(BuilderContext& context)
at Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)
at Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)
at Unity.Builder.BuilderContext.Resolve(Type type, String name)
at Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)
at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
at Unity.UnityContainer.<>c.<.ctor>b__73_2(BuilderStrategy[] chain, BuilderContext& context)
at Unity.Builder.BuilderContext.Resolve(Type type, String name, InternalRegistration registration)
at Unity.Builder.BuilderContext.Resolve(Type type, String name)
at Unity.Builder.BuilderContext.Resolve(ParameterInfo parameter, Object value)
at Unity.Processors.ConstructorProcessor.<>c__DisplayClass16_0.<GetResolverDelegate>b__0(BuilderContext& c)
at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
at Unity.Processors.MemberProcessor`2.<>c__DisplayClass8_0.<GetResolver>b__0(BuilderContext& c)
at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
at Unity.UnityContainer.<>c.<.ctor>b__73_1(BuilderContext& context)
at Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)
at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
--- End of inner exception stack trace ---
at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)````
解决方案
添加一个 Empty 构造函数,例如;
public PersonController() {};
//before
public PersonController(ICrudService<Person> personCrudservice)
{
this.personCrudservice = personCrudservice;
};
推荐阅读
- r - 带条件的 Dplyr 过滤器
- c# - Microsoft Teams for Android 中的自适应卡片怎么可能永远不会被裁剪(使用 c#)?
- algorithm - 如何在 k 个人中分配 n 个对象的 x 个副本
- reactjs - 可以手动测试 Web 应用程序吗?
- javascript - 如何从状态调度更新中删除功能依赖
- android - 具有约束布局的回收器视图项目 - 在运行时被推到一边
- python - 在 Python 数据框中的索引之间进行插值
- google-apps-script - 使用 Google 表格中的错误帐户打开 Google 脚本编辑器
- sql - 两个表上带有 where 子句的内部连接的 Postgres 索引
- java - 如何在动作监听器中进行算术计算