I'm in the process of upgrading from version 2.5.1 to version 3.1.0 and what used to work no long does. I'm attempting to resolve a factory that creates components that utilize generics. The error that is thrown is "ComponentActivator: could not proxy " where is the name of the factory that cannot be resolved
public class MyObject { }
public class MyContext { }
public class DummyComponent<T> : IDummyComponent<T> where T : MyObject { }
public interface IDummyComponent<T> { }
public interface IDummyComponentFactory
{
IDummyComponent<T> Create<T>(object o);
}
class Program
{
static void Main(string[] args)
{
var windsorContainer = new WindsorContainer();
windsorContainer.AddFacility<TypedFactoryFacility>()
.Register(
Component.For(typeof(IDummyComponent<>)).ImplementedBy(typeof(DummyComponent<>)),
Component.For<IDummyComponentFactory>().AsFactory());
var factory = windsorContainer.Resolve<IDummyComponentFactory>(); <-- Error Occurs Here
var myDummyComponent = factory.Create<MyObject>(new object());
}
}
This code is utilized in the following fashion within an Entity Framework repository for passing the EntityContext to another repository in order to handle deleted object like so:
public virtual IEnumerable<T> Where(Expression<Func<T, bool>> predicate, bool showDeleted = false, MergeOption mergeOption = MergeOption.AppendOnly)
{
if (typeof(IDeletable).IsAssignableFrom(typeof(T)))
{
var factory = Container.Instance.Resolve<IDeletableRepositoryFactory>();
var repository = factory.GetDeletableRepository<T>(EntityContext);
return repository.Where(predicate, showDeleted, mergeOption);
}
return GetObjectSet(mergeOption).Where(predicate);
}
Update: Including Inner Exception
System.Security.VerificationException
{"Operation could destabilize the runtime."} at
Castle.MicroKernel.Proxy.ProxyOptions.get_MixIns() in
c:\BuildAgent\work\5b096cace0fecb1f\src\Castle.Windsor\MicroKernel\Proxy\ProxyOptions.cs:line 96 at
Castle.Windsor.Proxy.DefaultProxyFactory.CreateProxyGenerationOptionsFrom(ProxyOptions proxyOptions, IKernel kernel, CreationContext context, ComponentModel model) in
c:\BuildAgent\work\5b096cace0fecb1f\src\Castle.Windsor\Windsor\Proxy\DefaultProxyFactory.cs:line 178 at
Castle.Windsor.Proxy.DefaultProxyFactory.Create(IKernel kernel, Object target, ComponentModel model, CreationContext context, Object[] constructorArguments) in
c:\BuildAgent\work\5b096cace0fecb1f\src\Castle.Windsor\Windsor\Proxy\DefaultProxyFactory.cs:line 105 at
Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, ConstructorCandidate constructor, Object[] arguments) in
c:\BuildAgent\work\5b096cace0fecb1f\src\Castle.Windsor\MicroKernel\ComponentActivator\DefaultComponentActivator.cs:line 123`
I tried running your code, but it works on my machine
This appears to be an issue with Intellitrace and is resolved by disabling it:
Tools -> Options -> IntelliTrace (uncheck Enable Intellitrace)
Found a reference to others having a similar issue.
Related
I know this sounds stupid. I'll provide some pieces of code and will try to explain as much.
Implementation #1 - Without name
Container = new UnityContainer();
Container.RegisterType<IFirstInterface, FirstImplementation>();
Container.RegisterType<IDifferentAssemblyInterface, DifferentAssemblyImplementation>();
Container.RegisterType<ISameAssemblyInterface, SameAssemblyImplementation>();
Implementation #2 - With name
const string configurationName = "simpleOption";
Container = new UnityContainer();
Container.RegisterType<IFirstInterface, FirstImplementation>(configurationName);
Container.RegisterType<IDifferentAssemblyInterface, DifferentAssemblyImplementation>(configurationName);
Container.RegisterType<ISameAssemblyInterface, SameAssemblyImplementation>(configurationName);
Observations
Implementation #1 works just fine. I used the immediate window and everything resolves.
With implementation #2 I used immediate window and everything from the same assembly resolves
Implementation #2 immediate window is not able to resolve exactly the IDifferentAssemblyInterface is not able to resolve
I opened up the Registrations constructor and all the dependencies are
Questions
Am I using named registration correctly?
Is passing the name as simple as that? Just pass a string while registering and the same string during resolve should work.
How do I debug/resolve this?
Sample Code
Program.cs
static IUnityContainer Container;
static void Main(string[] args)
{
// Arrange
Container = new UnityContainer();
Container.AddExtension(new Diagnostic());
Container.RegisterType<IMessageReader, ConsoleMessageReader>("Local");
Container.RegisterType<IMessageWriter, ConsoleMessageWriter>("Local");
Container.RegisterType<Startup, Startup>("Local");
Startup startup = Container.Resolve<Startup>("Local");
// Act
startup.Run();
}
Startup.cs
public class Startup
{
IMessageReader _reader;
IMessageWriter _writer;
public Startup(IMessageReader reader, IMessageWriter writer)
{
_reader = reader;
_writer = writer;
}
public void Run()
{
_writer.WriteMessage(_reader.ReadMessage());
}
}
Message ReaderWriter
public interface IMessageReader
{
string ReadMessage();
}
public class ConsoleMessageReader : IMessageReader
{
public string ReadMessage()
{
return "Hello, DI";
}
}
public interface IMessageWriter
{
void WriteMessage(string message);
}
public class ConsoleMessageWriter : IMessageWriter
{
public void WriteMessage(string message)
{
Console.WriteLine("{0}", message);
}
}
Error Message
Unhandled Exception: Unity.ResolutionFailedException: The current type, HelloDIApp.ConsoleClient.IMessageReader, is an interface and cannot be constructed. Are you missing a type mapping?
_____________________________________________________
Exception occurred while:
·resolving type: 'IMessageReader'
for parameter: 'reader'
on constructor: Startup(IMessageReader reader, IMessageWriter writer)
resolving type: 'Startup' registered with name: 'Local'
---> System.InvalidOperationException: The current type, HelloDIApp.ConsoleClient.IMessageReader, is an interface and cannot be constructed. Are you missing a type mapping? ---> Unity.Exceptions.InvalidRegistrationException: Exception of type 'Unity.Exceptions.InvalidRegistrationException' was thrown.
--- End of inner exception stack trace ---
at Unity.Processors.ConstructorDiagnostic.<>c.<GetResolver>b__11_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.UnityContainer.<>c__DisplayClass96_0.<OptimizingFactory>b__0(BuilderContext& c)
at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
at Unity.UnityContainer.ContextValidatingPlan(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.ParametersProcessor`1.<>c__DisplayClass1_0.<CreateDiagnosticParameterResolvers>b__0(BuilderContext& context)
at Unity.Processors.ConstructorDiagnostic.<>c__DisplayClass12_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.UnityContainer.<>c__DisplayClass96_0.<OptimizingFactory>b__0(BuilderContext& c)
at Unity.Strategies.BuildPlanStrategy.PreBuildUp(BuilderContext& context)
at Unity.UnityContainer.ExecuteValidatingPlan(BuilderContext& context)
--- End of inner exception stack trace ---
at Unity.UnityContainer.ExecuteValidatingPlan(BuilderContext& context)
at Unity.UnityContainer.Unity.IUnityContainer.Resolve(Type type, String name, ResolverOverride[] overrides)
at Unity.UnityContainerExtensions.Resolve[T](IUnityContainer container, String name, ResolverOverride[] overrides)
at HelloDIApp.ConsoleClient.Program.Main(String[] args) in C:\Code\HelloDI\HelloDIApp\HelloDIApp.ConsoleClient\Program.cs:line 18
Working Code
When I don't use names it works just fine.
static void Main(string[] args)
{
// Arrange
Container = new UnityContainer();
Container.AddExtension(new Diagnostic());
Container.RegisterType<IMessageReader, ConsoleMessageReader>();
Container.RegisterType<IMessageWriter, ConsoleMessageWriter>();
Container.RegisterType<Startup, Startup>();
Startup startup = Container.Resolve<Startup>();
// Act
startup.Run();
}
Found one way of doing it. I am still looking for answers.
While constructing complex objects we can inform unity about how we want to cherry pick our dependencies. We can play around with all the combinations of different names and create a dependency map. Upon resolving, Unity will go and build exactly as per the order under that name.
static void Main(string[] args)
{
// Arrange
Container = new UnityContainer();
Container.AddExtension(new Diagnostic());
Container.RegisterType<IMessageReader, ConsoleMessageReader>();
Container.RegisterType<IMessageWriter, ConsoleMessageWriter>();
Container.RegisterType<IMessageReader, TwitterMessageReader>("Social");
Container.RegisterType<IMessageWriter, FacebookMessageWriter>("Social");
Container.RegisterType<IStartup, Startup>("Social", new InjectionConstructor(new ResolvedParameter<IMessageReader>("Social"), new ResolvedParameter<IMessageWriter>("Social")));
Container.RegisterType<IMessageReader, ConsoleMessageReader>("Local");
Container.RegisterType<IMessageWriter, ConsoleMessageWriter>("Local");
var reader = Container.Resolve<IMessageReader>("Social");
var writer = Container.Resolve<IMessageWriter>();
Container.RegisterType<IStartup, Startup>("Local", new InjectionConstructor(reader, writer));
IStartup startup = Container.Resolve<IStartup>("Local");
// Act
startup.Run();
}
I've tried following advice from existing posts to make HttpRequestMessage available as a constructor dependency for services in Web API:
ASP Web Api - IoC - Resolve HttpRequestMessage
Resolving HttpControllerContext with Castle Windsor
This advice works fine if all the dependencies only have one constructor. But when a dependency has multiple constructors, dependency resolution fails.
Any ideas how to extend the idea to work with multiple constructors?
=======================
The existing approach is summarised as follows:
First you add the HttpRequestMessage as an additional named argument when resolving the controller in your IHttpControllerActivator:
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller = (IHttpController)container.Resolve(
controllerType,
new { request });
Then you propagate this argument in the CreationContext:
public class InlineDependenciesPropagatingDependencyResolver :
DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(
CreationContext current,
Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
This works fine when all the dependencies only have one constructor.
In my case, I have a hierarchy of dependencies:
The controller depends on IServiceA
ServiceA depends on IServiceB
ServiceB depends on IServiceC
ServiceC depends on HttpRequestMessage
Where ServiceC looks like this:
public class ServiceC: IServiceC
{
private readonly HttpRequestMessage request;
public ServiceC(HttpRequestMessage request)
{
this.request = request;
}
And ServiceB has two constructors:
public class ServiceB: IServiceB
{
public ServiceB(string paramForTests)
{
// Do stuff
}
public ServiceB(IServiceC serviceC)
{
// Do stuff
}
But then Windsor fails to resolve ServiceC.
The problem seems to be in the SelectEligibleConstructor logic of DefaultComponentActivator. It calls into the CanResolve method in DefaultDependencyResolver which eventually ends up at:
protected virtual bool CanResolveFromKernel(CreationContext context, ComponentModel model, DependencyModel dependency)
{
if (dependency.ReferencedComponentName != null)
{
// User wants to override
return HasComponentInValidState(dependency.ReferencedComponentName, dependency, context);
}
if (dependency.Parameter != null)
{
return true;
}
if (typeof(IKernel).IsAssignableFrom(dependency.TargetItemType))
{
return true;
}
if (dependency.TargetItemType.IsPrimitiveType())
{
return false;
}
return HasAnyComponentInValidState(dependency.TargetItemType, dependency, context);
}
And then HasAnyComponentInValidState just looks at whether ServiceC has already been resolved, it doesn't actually check whether it can be resolved.
If there is only one constructor, then the code calls the Resolve methods, which correctly recursively resolve the dependencies, and ServiceC is available ok.
I don't want to limit my services to only having one constructor (or use the [DoNotSelect] attribute to only leave one for Castle to look at).
Any ideas how to inject arguments as I have done, and still have it work with multiple constructors?
I found an alternative way of resolving the HttpRequestMessage parameter, which now works.
Just use a factory method to spin up the service with the dependency on HttpRequestMessage, where you manually extract the required "request" argument from the context which has been passed down from the controller activator:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component
.For<IServiceC>()
.UsingFactoryMethod((kernel, context) => {
var request = (HttpRequestMessage)context.AdditionalArguments["request"];
var serviceC = new ServiceC(request);
return serviceC;
})
.LifestyleTransient()
);
}
}
Im trying to implement CQRS pattern to my app. So I found how to register all command handlers from assembly here : Autofac resolve dependency in CQRS CommandDispatcher
But it doesnt work well for me. Here is the code:
containerBuilder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
containerBuilder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(IQueryHandler<,>));
Handlers factory
public class CqrsHandlerFactory : ICqrsHandlerFactory
{
private readonly IContainer container;
public CqrsHandlerFactory(IContainer container)
{
this.container = container;
}
public ICommandHandler<TCommand> GetCommandHandler<TCommand>(TCommand command) where TCommand : class, ICommand
{
return container.Resolve<ICommandHandler<TCommand>>();
}
public IQueryHandler<TQuery, object> GetQueryHandler<TQuery>(TQuery query) where TQuery : class, IQuery
{
return container.Resolve<IQueryHandler<TQuery, object>>();
}
}
Bus
public class CqrsBus : ICqrsBus
{
private readonly ICqrsHandlerFactory cqrsHandlerFactory;
public CqrsBus(ICqrsHandlerFactory cqrsHandlerFactory)
{
this.cqrsHandlerFactory = cqrsHandlerFactory;
}
public void ExecuteCommand(ICommand command)
{
var handler = cqrsHandlerFactory.GetCommandHandler(command);
if (handler == null)
throw new NotImplementedHandlerException(string.Format("Cannot find handler for {0}", command.GetType()));
handler.Handle(command);
}
public TResult RunQuery<TResult>(IQuery query)
{
var handler = cqrsHandlerFactory.GetQueryHandler(query);
if (handler == null)
throw new NotImplementedHandlerException(string.Format("Cannot find handler for {0}", query.GetType()));
return (TResult)handler.Handle(query);
}
}
Exception
An exception of type 'Autofac.Core.Registration.ComponentNotRegisteredException' occurred in Autofac.dll but was not handled in user code
Additional information: The requested service 'PromocjeWsieciowkach.Messaging.Core.ICommandHandler`1[[PromocjeWsieciowkach.Messaging.Core.ICommand, PromocjeWsieciowkach.Messaging.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Stacktrace
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable1 parameters)
at PromocjeWsieciowkach.Messaging.Factories.CqrsHandlerFactory.GetCommandHandler[TCommand](TCommand command) in C:\Users\Daniel\Desktop\PromocjeWsieciowkach\src\PromocjeWsieciowkach.Messaging\Factories\CqrsHandlersFactory.cs:line 17
at PromocjeWsieciowkach.Messaging.Bus.CqrsBus.ExecuteCommand(ICommand command) in C:\Users\Daniel\Desktop\PromocjeWsieciowkach\src\PromocjeWsieciowkach.Messaging\Bus\CqrsBus.cs:line 17
at PromocjeWsieciowkach.Controllers.PostController.Index() in C:\Users\Daniel\Desktop\PromocjeWsieciowkach\src\PromocjeWsieciowkach\Controllers\PostController.cs:line 20
at lambda_method(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__28.MoveNext()
So what i'am doing wrong?
Your code and the exception message clearly show the problem. In summary, your exception message explains that:
The requested service 'ICommandHandler<ICommand>' has not been registered.
In other words, you are requesting an ICommandHandler<ICommand> instead of an ICommandHandler<TestCommand>. This can be seen here:
public void ExecuteCommand(ICommand command)
{
var handler = cqrsHandlerFactory.GetCommandHandler(command);
// ...
}
The C# compiler applied type inference to the GetCommandHandler<T> call. So the following code is the actual call:
var handler = cqrsHandlerFactory.GetCommandHandler<ICommand>(command);
You should change the ICrqsBus.ExecuteCommand method to the following:
public void ExecuteCommand<TCommand>(TCommand command)
{
// You can merge the factory and your CqrsBus. Splitting them is useless.
var handler = cqrsHandlerFactory.GetCommandHandler<TCommand>();
// You don't need then null check; Autofac never returns null.
handler.Handle(command);
}
If you can't make the ExecuteCommand method generic (e.g. because you don't know the command type at compile time), you should build the generic types using the reflection API as follows:
public class CqrsBus : ICqrsBus
{
private readonly IComponentContext context;
public CqrsBus(IComponentContext context)
{
this.context = context;
}
public void ExecuteCommand(ICommand command)
{
Type handlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
dynamic handler = this.context.Resolve(handlerType);
void handler.Execute((dynamic)command);
}
}
It's also worth noting that if your using nopcommerce and adding a service, the same error is generated if you forget to add your service in the dependancy registrar.
builder.RegisterType<YourService>().As<IYourService>().InstancePerLifetimeScope();
Just came across this myself, and the following quote:
The requested service 'ICommandHandler' has not been registered."
Made me realise about the dependancy registrar.
Thanks Steven
I'm having two problems, the first is scaling and became visible while load testing.
Under load, things quickly (10 concurrent or less) fail with the error:
There is already an open DataReader associated with this Command which must be closed first.
Or
ExecuteReader requires an open and available Connection. The connection's current state is open.
The stack trace references a repository every time, example:
Line 23: public AboutViewDto GetAboutView()
Line 24: {
Line 25: var featured = UnitOfWork.FaqRepository
Line 26: .GetFeatured()
Original NinjectDependencyResolver:
public class NinjectDependencyResolver
: IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
private readonly IKernel _kernel;
public NinjectDependencyResolver() : this(new StandardKernel())
{
}
public NinjectDependencyResolver(IKernel kernel)
{
_kernel = kernel;
AddBindings(_kernel);
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType);
}
public void Dispose()
{
// nothing??
}
private static void AddBindings(IBindingRoot kernel)
{
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InSingletonScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InSingletonScope();
kernel.Bind<IFaqRepository>().To<FaqRepository>().InSingletonScope();
kernel.Bind<IListValueRepository>().To<ListValueRepository>().InSingletonScope();
kernel.Bind<INoticeRepository>().To<NoticeRepository>().InSingletonScope();
kernel.Bind<IOrganizationRepository>().To<OrganizationRepository>().InSingletonScope();
kernel.Bind<ITagRepository>().To<TagRepository>().InSingletonScope();
kernel.Bind<IAdminService>().To<AdminService>();
kernel.Bind<IAutoMapperService>().To<AutoMapperService>();
kernel.Bind<IHomeService>().To<HomeService>();
kernel.Bind<IInfoService>().To<InfoService>();
kernel.Bind<IMailService>().To<MailService>();
kernel.Bind<INoticeService>().To<NoticeService>();
kernel.Bind<IOrganizationService>().To<OrganizationService>();
kernel.Bind<ISearchService>().To<SearchService>();
kernel.Bind<IValidator<QuestionDto>>().To<QuestionDtoValidator>();
kernel.Bind<IValidator<NoticeCommentDto>>().To<CommentDtoValidator>();
kernel.Bind<IValidator<NoticeContactDto>>().To<NoticeContactDtoValidator>();
kernel.Bind<IValidator<NoticeDto>>().To<NoticeDtoValidator>();
kernel.Bind<IValidator<OrganizationDto>>().To<OrganizationDtoValidator>();
}
}
}
I had a hunch that InSingletonScope() was causing the problem so I changed it to:
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
And changed all of the other SingletonScopes to RequestScope.
After making that change, the site handles 400+ concurrent users without any failures, however...
Now no commits work against the database. I can trace the calls through the controller, to the service, to the repository, and to the DBContext commit, but the inserts or updates are not happening.
I'll post snippets of each item here in hopes someone can spot the dumb error we've made or suggest improvements.
Snippets follow:
Activity, update a Notice, everything involved:
1) Ninject:
kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
kernel.Bind<INoticeService>().To<NoticeService>();
.. etc...
2) Controller:
public sealed class NoticeController : BaseController
{
public NoticeController(IAutoMapperService autoMapperService, INoticeService noticeService)
{
AutoMapperService = autoMapperService;
NoticeService = noticeService;
}
...
3) NoticeService
public class NoticeService : BaseService, INoticeService
{
public NoticeService(
IUnitOfWork unitOfWork,
IAutoMapperService autoMapperService,
IValidator<NoticeDto> noticeDtoValidator)
: base(unitOfWork)
{
AutoMapperService = autoMapperService;
NoticeDtoValidator = noticeDtoValidator;
}
4) Unit of Work
public class UnitOfWork : IUnitOfWork
{
private IDataContext _dataContext;
private bool _disposed;
private ObjectContext _objectContext;
private DbTransaction _transaction;
public UnitOfWork(
IDataContext dataContext,
INoticeRepository noticeRepository)
{
_dataContext = dataContext;
NoticeRepository = noticeRepository;
}
5) Notice Repository
public class NoticeRepository : Repository<Notice>, INoticeRepository
{
public NoticeRepository(IDataContext context) : base(context)
{
}
...
6) Controller Action
public ActionResult Create(NoticeViewModel notice)
{
notice.TypeId = Convert.ToInt32(NoticeType.ManuallyEnteredDocument);
var newNotice = AutoMapperService.Map<NoticeViewModel, NoticeDto>(notice);
NoticeService.Create(newNotice);
return RedirectToAction("Details", new { name = notice.Arc });
}
7) NoticeService.Create(new):
public void Create(NoticeDto notice)
{
NoticeDtoValidator.ValidateAndThrow(notice);
var newNotice = AutoMapperService.Map<NoticeDto, Notice>(notice);
UnitOfWork.NoticeRepository.Add(newNotice);
UnitOfWork.SaveChanges();
}
8) Generic Repository Add():
public virtual void Add(TEntity entity)
{
entity.ObjectState = ObjectState.Added;
_dbSet.Attach(entity);
_context.SyncObjectState(entity);
}
9) UnitOfWork SaveChanges():
public int SaveChanges()
{
return _dataContext.SaveChanges();
}
When I step through this, the entity that is attached in #8 looks right, the status is added, when save changes is called there are no changes recorded in the base SaveChanges():
public override int SaveChanges()
{
SyncObjectsStatePreCommit();
base.ChangeTracker.DetectChanges();
var result = base.ChangeTracker.HasChanges();
var changes = base.SaveChanges();
result here is false
How could that be? What am I missing, other than abstraction hell and UoW/Repos on top of EF6 context, (I inherited this).
Someone out there see anything ELSE dumb?
No errors, no exceptions, the inserts just don't happen.
Problem solved, the issue was that Ninject was injecting a different context into our repositories.
We found two ways to solve this:
Option 1) In our unit of work we created an additional constructor that just receives a dbcontext and creates new repositories passing them the dbcontext. We left the old constructor as well so we can inject the repos for testing. This worked great and was a trivial change to make.
Option 2) Removed Ninject and overloaded the constructors for each Controller, manually creating the items. Since this project was small, we only had to touch 6 controllers and it worked fine, just 4 new lines of code in each. We left the old constructor as well so we can inject the services for testing.
I used nuget to update my project to signalr 2.2 and structure map 2.6.4.
Now when my program attempts to use SignalR, structure map is throwing this error:
StructureMap.StructureMapException was unhandled by user code
HResult=-2146232832
Message=StructureMap Exception Code: 202
No Default Instance defined for
PluginFamily Microsoft.AspNet.SignalR.Messaging.IMessageBus, Microsoft.AspNet.SignalR.Core, Version=2.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Source=StructureMap
My code hasn't change and I don't believe I'm requiring IMessageBus anywhere, so I'm not sure why structure map is now doing this. I setup a new project with a simplified structuremap 2.6.4/signalr 2.2 and never need to seed IMessageBus, so it's something about my implementation, but I'm not sure what's changed from the upgrade.
Does anyone have an idea to point me to?
Thanks!
Scott
This was solved by first looking to resolve in the base class:
public override object GetService(Type serviceType)
{
if (serviceType == null)
return null;
var service = base.GetService(serviceType);
if (service != null) return service;
return container.TryGetInstance(serviceType);
}
What solved this for me was making a change to the GetService method as well. Here is my full StrucutreMapSignalRDependencyResolver for reference:
public class StructureMapSignalRDependencyResolver : DefaultDependencyResolver
{
private readonly IContainer _container;
public StructureMapSignalRDependencyResolver(IContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
return _container.TryGetInstance(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
var objects = _container.GetAllInstances(serviceType).Cast<object>();
return objects.Concat(base.GetServices(serviceType));
}
}