I've been dealing with this issue for a while, and still can't seem to find a solution. I have several repositories which wrap an EF 4 ObjectContext. An example is below:
public class HGGameRepository : IGameRepository, IDisposable
{
private readonly HGEntities _context;
public HGGameRepository(HGEntities context)
{
this._context = context;
}
// methods
public void SaveGame(Game game)
{
if (game.GameID > 0)
{
_context.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Modified);
}
else
{
_context.Games.AddObject(game);
}
_context.SaveChanges();
}
public void Dispose()
{
if (this._context != null)
{
this._context.Dispose();
}
}
}
And I have the following NinjectModule:
public class DIModule : NinjectModule
{
public override void Load()
{
this.Bind<HGEntities>().ToSelf();
this.Bind<IArticleRepository>().To<HGArticleRepository>();
this.Bind<IGameRepository>().To<HGGameRepository>();
this.Bind<INewsRepository>().To<HGNewsRepository>();
this.Bind<ErrorController>().ToSelf();
}
}
Since I'm using the MVC 2 extension, these bindings default to InRequestScope().
My problem is that the ObjectContext isn't being handled properly. I get what's described here: https://stackoverflow.com/a/5275849/399584 Specifically, I get an InvalidOperationException that states:
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
This happens every time I try to update an Entity.
If I set my repos to bind InSingletonScope() it works, but seems like a bad idea.
What am I doing wrong?
EDIT: For clarity, I have just one ObjectContext that I want to share with all my repos per request.
You have to specify InRequestScope() in your module. Based on this article the default to transient, which is why you are getting more than one context.
public class DIModule : NinjectModule
{
public override void Load()
{
this.Bind<HGEntities>().ToSelf().InRequestScope();
this.Bind<IArticleRepository>().To<HGArticleRepository>().InRequestScope();
this.Bind<IGameRepository>().To<HGGameRepository>().InRequestScope();
this.Bind<INewsRepository>().To<HGNewsRepository>().InRequestScope();
this.Bind<ErrorController>().ToSelf().InRequestScope();
}
}
Also did you add ninject to your project via nuget package manager or the old fashion way?
Related
Example: I have a countries catalog stored in another DB and I need to use it as a property in some ContentParts. I'm trying to make the connection without interfering much with Orchard wiring.
public class MoviePart : ContentPart<MoviePartRecord>
{
public IEnumerable<CountryRecord> Countries
{
get
{
return Record.Countries.Select(r => r.CountryRecord);
}
}
}
The relation between CountryRecords and MovieParts will be on the Orchard DB, but the CountryRecord data is in another DB. I only need Read access, but I don't get which and how to override the Handler to use the other source.
Do I need to create a ContentHandler and override all methods, and create another StorageFilter that uses the new repository with the external source? And how would I inject the new repo into the handler?
public class CountryPartHandler : ContentHandler
{
public CountryPartHandler(IRepository<CountryPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
}
protected override void Loading(LoadContentContext context)
{
base.Loading(context);
}
}
Update:
In this Using External Data with Orchard (around 25th min) video, he seems to be doing what I need with this code:
public ProductPartHandler(IRepository<ProductPartRecord> repository, Work<IProductService> productServiceWork)
{
Filters.Add(StorageFilter.For(repository));
OnActivated<ProductPart>((context, part) => {
part.ProductField.Loader(() => productServiceWork.Value.GetProduct(part.Id));
});
}
But in my code it can't find the "Loader" function, even though I have all the references from the video too, so maybe ProductField is a custom type?
So that is a lazy field on the part, something like this:
public class MyPart : ContentPart {
internal readonly LazyField<CustomData> CustomDataField = new LazyField<CustomData>();
public CustomData CustomData {
get { return CustomDataField.Value; }
}
}
public class CustomData {
...
}
public class MyPartHandler : ContentPartHandler {
private ICustomService _customService;
public MyPartHandler(ICustomService customService){
_customService = customService;
OnActivated<MyPart>(Initialize);
}
private void Initialize(ActivatedContentContext context, MyPart part){
part.CustomDataField.Loader(() => {
return _customService.Get(part.ContentItem.Id);
});
}
}
I don't know how you are loading your external data, whether via rest, wcf etc., but the logic can just be thrown into the custom service
Given below are my different class declarations and how I am trying to setup unity container configuration to get a Interface to Concrete class implementation. The code currently throws either an stackoverflow exception or suggests that a interface cannot be constructed.
Please help me fix, either the class structure or the container configuration.
CodesController Class -
public class CodesController : ApiController
{
private readonly IUnitOfWorkAsync unitOfWork;
private readonly ICodeRepository repository;
public CodesController(IUnitOfWorkAsync unitOfWork, ICodeRepository codeRepository)
{
if (unitOfWork == null)
{
throw new ArgumentNullException("unitOfWork");
}
this.unitOfWork = unitOfWork;
this.repository = codeRepository;
}
//Other class level methods here
}
CodeRepository class -
public class CodeRepository : ICodeRepository
{
private readonly ICodeRepository codeRepository;
public CodeRepository(ICodeRepository repository)
{
this.codeRepository = repository;
}
public virtual async Task<IEnumerable<Code>> GetCodeAsync(string codeKey)
{ //Some implementation here}
}
ICodeRepository Interface -
public interface ICodeRepository : IRepositoryAsync<Code>
{
Task<IEnumerable<Code>> GetCodeAsync(string codeKey);
}
IRepositoryAsync Interface -
public interface IRepositoryAsync<TEntity> : IRepository<TEntity> where TEntity : class, IPersistenceHint
{
Task<bool> DeleteAsync(params object[] keyValues);
Task<bool> DeleteAsync(CancellationToken cancellationToken, params object[] keyValues);
Task<TEntity> FindAsync(params object[] keyValues);
Task<TEntity> FindAsync(CancellationToken cancellationToken, params object[] keyValues);
}
Unity Container Configuration-
container.RegisterType<IUnitOfWorkAsync, UnitOfWork>(
"test",
new TransientLifetimeManager(),
new InjectionConstructor(container.Resolve<IDataContextAsync>("test")));
container.RegisterType<ICodeRepository, CodeRepository>();
container.RegisterType<CodesController, CodesController>();
With this given configuration and class structure, based on my experimentation with container config, I get following exception -
JSON
exceptionMessage=An error occurred when trying to create a controller of type 'CodesController'. Make sure that the controller has a parameterless public constructor.
exceptionType=System.InvalidOperationException
innerException
exceptionMessage=Type '<Namespace>.Api.Controllers.CodesController' does not have a default constructor
stackTrace= at System.Linq.Expressions.Expression.New(Type type)
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
Please suggest, if anything is wrong here, so that I can fix the same. Already struggling many days on this.
You're injecting ICodeRepository to CodeRepository, which probably causes to stackoverflow exception, since it will keep generating ICodeRepositories. It will generate a recursive call. Somewhat like this one:
public class BaseFoo
{
public BaseFoo(BaseFoo foo){ }
}
public class Foo : BaseFoo
{
public Foo() : base(new Foo()) { }
}
And regarding the "does not have a default constructor"-exception, have you registered a DependencyResolver for Web API? See one of these questions for more detailed information how to do it:
Using Unity with Web Api 2 gives error does not have a default constructor
Unity.WebApi | Make sure that the controller has a parameterless public constructor
ASP.Net MVC 4 Web API controller dosn't work with Unity.WebApi
As a side note, you shouldn't have to register the CodesController in your unity registration.
Consider the following existing classes which uses MEF to compose Consumer.
public interface IProducer
{
void Produce();
}
[Export(typeof(IProducer))]
public class Producer : IProducer
{
public Producer()
{
// perform some initialization
}
public void Produce()
{
// produce something
}
}
public class Consumer
{
[Import]
public IProducer Producer
{
get;
set;
}
[ImportingConstructor]
public Consumer(IProducer producer)
{
Producer = producer;
}
public void DoSomething()
{
// do something
Producer.Produce();
}
}
However, the creation of Producer has become complex enough that it can no longer be done within the constructor and the default behavior no longer suffices.
I'd like to introduce a factory and register it using a custom FactoryAttribute on the producer itself. This is what I have in mind:
[Export(typeof(IProducer))]
[Factory(typeof(ProducerFactory))]
public class Producer : IProducer
{
public Producer()
{
// perform some initialization
}
public void Produce()
{
// produce something
}
}
[Export]
public class ProducerFactory
{
public Producer Create()
{
// Perform complex initialization
return new Producer();
}
}
public class FactoryAttribute : Attribute
{
public Type ObjectType
{
get;
private set;
}
public FactoryAttribute(Type objectType)
{
ObjectType = objectType;
}
}
If I had to write the "new" code myself, it may very well look as follows. It would use the factory attribute, if it exists, to create a part, or default to the MEF to create it.
public object Create(Type partType, CompositionContainer container)
{
var attribute = (FactoryAttribute)partType.GetCustomAttributes(typeof (FactoryAttribute), true).FirstOrDefault();
if (attribute == null)
{
var result = container.GetExports(partType, null, null).First();
return result.Value;
}
else
{
var factoryExport = container.GetExports(attribute.ObjectType, null, null).First();
var factory = factoryExport.Value;
var method = factory.GetType().GetMethod("Create");
var result = method.Invoke(factory, new object[0]);
container.ComposeParts(result);
return result;
}
}
There are a number of articles how to implement a ExportProvider, including:
MEF + Object Factories using Export Provider
Dynamic Instantiation
However, the examples are not ideal when
The application has no dependencies or knowledge of Producer, only IProducer. It would not be able to register the factory when the CompositionContainer is created.
Producer is reused by several applications and a developer may mistakenly forget to register the factory when the CompositionContainer is created.
There are a large number of types that require custom factories and it may pose a maintenance nightmare to remember to register factories when the CompositionContainer is created.
I started to create a ExportProvider (assuming this would provide the means to implement construction using factory).
public class FactoryExportProvider : ExportProvider
{
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
AtomicComposition atomicComposition)
{
// What to do here?
}
}
However, I'm having trouble understanding how to tell MEF to use the factory objects defined in the FactoryAttribute, and use the default creation mechanism if no such attribute exists.
What is the correct manner to implement this? I'm using MEF 2 Preview 5 and .NET 4.
You can make use of a property export:
public class ProducerExporter
{
[Export]
public IProducer MyProducer
{
get
{
var producer = new Producer();
// complex initialization here
return producer;
}
}
}
Note that the term factory isn't really appropriate for your example, I would reserve that term for the case where the importer wants to create instances at will, possibly by providing one or more parameters. That could be done with a method export:
public class ProducerFactory
{
[Export(typeof(Func<Type1,Type2,IProducer>)]
public IProducer CreateProducer(Type1 arg1, Type2 arg2)
{
return new Producer(arg1, arg2);
}
}
On the import side, you would then import a Func<Type1,Type2,IProducer> that you can invoke at will to create new instances.
Given this class:
class Foo
{
readonly ILog log;
public Foo(ILog log)
{
this.log = log;
}
...
}
I'd like to configure Unity to inject ILog. That's easy:
container.RegisterInstance<ILog>(LogManager.GetLogger(typeof(XYZ)));
But I'd like to make Unity call LogManager.GetLogger with the type of the parent type being resolved.
This is close:
container.RegisterType<ILog>(new InjectionFactory((c, t, s) => LogManager.GetLogger(t)));
But t in this case is the type being resolved (ILog), not the type that the object is being resolved for (Foo).
I know I can do this:
container.RegisterType<Foo>(new InjectionFactory(c => new Foo(LogManager.GetLogger(typeof(Foo)));
But I don't want to have to add that crazy declaration every time I register an object.
I know this can be done in Autofac, and I know the Real Answer is not to use Unity in the first place, but can this be done? :)
Unity might not give you all the goodies some of the other containers offer but I have yet to find a feature you can't easily add.
var container = new UnityContainer();
container.AddNewExtension<TrackingExtension>();
container.RegisterType<ILog>(
new InjectionFactory((ctr, type, name) =>
{
var tracker = ctr.Resolve<ITracker>();
var parentType = tracker.CurrentBuildNode.Parent.BuildKey.Type;
return LogManager.GetLogger(parentType);
}));
var sut = container.Resolve<UsesLog>();
Assert.AreEqual(typeof(UsesLog), sut.Log.Type);
You can find the source code for the TrackingExtension here. Its located in the TecX.Unity project folder.
If you want a DI container to return you a logger based on the class’ type information, then put the type information into the public interface so the DI container can see it. It removes the need for any container specific override features and then it won’t matter if you are using Unity or AutoFac.
Someone that knows the log4net object model well might be able to give you a more efficient implementation, but try something like this:
using System;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnityLoging
{
public interface ILog<T> : log4net.ILog
{ }
public class MyLogger<T> : log4net.Core.LogImpl, ILog<T>
{
public MyLogger() : base(log4net.LogManager.GetLogger(typeof(T).Name).Logger)
{ }
}
public class ClassToLog
{
private readonly log4net.ILog log;
public ClassToLog(ILog<ClassToLog> log)
{
this.log = log;
}
public void LogMe()
{
log.Debug("Got here");
}
}
[TestClass]
public class TestClass
{
[TestMethod]
public void GenericLogRegistrationTest()
{
log4net.Config.XmlConfigurator.Configure();
IUnityContainer container = new UnityContainer();
container.RegisterType(typeof(ILog<>), typeof(MyLogger<>));
ClassToLog c = container.Resolve<ClassToLog>();
c.LogMe();
log4net.LogManager.Shutdown();
}
}
}
This seems like a very clean approach: https://github.com/roblevine/UnityLoggingExtensions
Is there any potential problem in setting datacontext as property like this:
repository
public Repository()
{
public DataContext dc {get;set;}
public GetOrders(int id)
{ ...from dc.Orders...}
}
service layer:
public GetNewOrders()
{
....
Repository rep=new Repository();
using {DataContext dc=new DataContext())
{
rep.dc=dc;
rep.GetOrders(id);
}
}
From what I have read, using the DataContext "for more than one business conversation is usually the wrong thing to do." Scroll down to the Why Is This Important? section for the quote. Due to caching and other factors, you should consider your DataContext stale immediately. From that, it is safe to say you don't want to keep the DataContext as a property that is reused by all your methods. Using Eric Duncan's suggestion, you will want to pass in some kind of DataContext factory to get a new context for each query.
For a discussion focused on the DataContext, the APress Pro LINQ book has an entire chapter on the DataContext, the very last page of which also advises you to "consider the DataContext stale immediately."
In DDD, you're missing the bigger picture here by referencing the concret classes. You are not interfacing between the Repository and "Services layer" by best practices. If you must have DataContext injected into the Repository, I would recommend refactoring to:
public interface IRepository
{
IList<Orders> GetNewOrders();
}
public Repository : IRepository
{
private IDataContext _dataContext;
public Repository(IDataContext dataContext)
{
_dataContext = dataContext;
}
public IList<Orders> GetNewOrders()
{
// perform your actions on _dataContext here
}
}
The better solution would be to let the Repository handle the DataContext on its own - keeping the seperation of concert valid by masking the underlying requirements:
public interface IRepository
{
IList<Orders> GetNewOrders();
}
public Repository : IRepository
{
private IDataContext _dataContext;
public Repository(String connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IList<Orders> GetNewOrders()
{
// perform your actions on _dataContext here
}
}
If you must keep control of the DataContext (or another class) yourself (perhaps you want to keep a static reference around, or change settings based on an WebRequest, etc), you you will need to use a "Factory".
The factory would look something like this:
public static class DataContextFactory
{
public static IDataContext GetInstance()
{
// return either a static instance,
// or threaded instance, a GlobalContext instance
// or whatever your preference is here
//
}
}
That way, you have full control over how the instance of DataContext is controlled outside and away from your "Services" layer. So, you would use this DataContextFactory like the following:
public interface IRepository
{
IList<Orders> GetNewOrders();
}
public Repository : IRepository
{
public IList<Orders> GetNewOrders()
{
using (var dataContext = DataContextFactory.GetInstance())
{
// dataContext is now your IDataContext to work with
}
}
}
"How to access the IRepository?" you may ask?
Your services layer would do something like:
public void GetNewOrdersForServices()
{
// Not recommended!
// IRepository repo = new Repository()
//
// The following is recommended instead; because, it removes the
// the Concret reference from your Services layer completely!
//
IRepository repo = ServiceLocator.InstanceOf<IRepository>();
IList myList = repo.GetNewOrders();
}
Or, you would inject it into the constructor of your service using your favorite flavor of Inversion of Control container like so:
public class OrderService
{
private IRepository _repo;
public OrderService(IRepository repo)
{
_repo = repo;
}
public void GetNewOrdersForServices()
{
IList myList = _repo.GetNewOrders();
}
If you are not fimilar with the service locator concepts, check out Castle Windsor as it Encapsulates just about all your needs.