Following is my register code
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
new InjectionParameter<IBar2>(CreateBar2(container)))
Problem is CreateBar2(container) is only called once when program startup, I need it called everytime IFoo resolved
Another question, which one is best practice
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
new InjectionParameter<IBar2>(CreateBar2(container)))
or
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
CreateBar2(container))
First, you need to use a different LifetimeManager. TransientLifetimeManager will resolve a new instance every time.
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
new InjectionParameter<IBar2>(CreateBar2(container)),
new TransientLifetimeManager())
This means that every time IFoo is injected or resolved it will call the constructor each time. However, it seems as you're injecting a method, which will be executed at registration - CreateBar2(container). It's the same thing as writing:
var bar2 = CreateBar2(container); // Called once.
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
new InjectionParameter<IBar2>(bar2))
I recomend you to abstract this to a class instead and injecting it. This way you can control the calls to that as well.
public interface ICreateBar2
{
IBar CreateBar2();
}
public class CreateBar2
{
private IUnityContainer _container;
public CreateBar(IUnityContainer container)
{
_container = container;
}
public IBar CreateBar2()
{
// Do stuff.
return CreateBar2(_container); // Or what you need to do?
}
}
And change your registration to
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
new ResolvedParameter<ICreateBar2>),
new TransientLifetimeManager())
container.RegisterType<ICreateBar2, CreateBar2>(new TransientLifetimeManager());
Or possibly RegisterInstance, if it better suits your needs?
Remember to change the constructor of IFoo to accept ICreateBar instead. The best thing with this approach is that you don't need the InjectionConstructor anymore, since all parameters can be resolved by Unity.
container.RegisterType<IFoo, Foo>(new TransientLifetimeManager());
If your REALLY need to keep the CreateBar2()-method in the current scope, you can inject a Func which actually returns the same value as CreateBar2().
I do not know the complete signature of CreateBar(), but you can do something like this:
container.RegisterType<IFoo, Foo>(
new InjectionConstructor(typeof (IEnumerable<int>),
new ResolvedParameter<IBar1>,
new InjectionParameter<Func<IBar2>>(
new Func<IBar2>(()=> CreateBar2(container)));
But now you need to inject Func<IBar2> to the IFoo constructor. This will cause it to execute whenever you use it in the constructor.
public class Foo : IFoo
{
IBar1 _bar1;
IBar2 _bar2;
public Bar(IBar1 bar1, Func<IBar2> bar2Func)
{
_bar1 = bar1;
_bar2 = bar2Func();
}
}
Related
I'm trying to explicitly create a db context in .NET Core 3 startup
I know I can do this in startup.cs ConfigureServices to inject a dbcontext into the controller (which works fine):
String dbconn = Configuration["ConnectionStrings:VerseDBConnectionStringMSSQL"];
services.AddDbContext<VerseDBContext>(options => options.UseSqlServer(dbconn));
but I am trying to generalize the storage provider (and keep the controller code the same for all storage readers), so it takes an IVerseStorageReader interface, instead of a DB context (as I may want to read from memory, or xmlfile, etc) and use the same code in the controller, just switch it based on config in appsettings. One of the VerseStorageReaders takes a db context in constructor:
public class DBVerseReader : IVerseStorageReader
{
private VerseDBContext _dbContext;
public DBVerseReader(VerseDBContext dbContext)
{
_dbContext = dbContext;
}
...
}
My problem is: I can't quite figure out the syntax right for creating the db context explicitly. I'm very close (I think) but this doesn't work:
String dbconn = Configuration["ConnectionStrings:VerseDBConnectionStringMySQL"];
var optionsBuilder = new DbContextOptionsBuilder<VerseDBContext>();
optionsBuilder.UseMySql(dbconn);
VerseDBContext x = optionsBuilder.UseMySql<VerseDBContext>(dbconn); <-- compile error
services.AddSingleton<IVerseStorageReader>(new DBVerseReader(x));
Can someone clue me on what I'm doing wrong? What I'm trying to inject is an instance of IVerseStorageReader, not a DBContext. There are overloads of VerseStorageReader that take a db context as input, and others which take other inputs (e.g. xmlfilename, etc)...so I want startup to add an instance of one of the IVerseStorageReaders and that gets injected (not a dbcontext injection).
You have to get the options from the builder after configuring it
String dbconn = Configuration["ConnectionStrings:VerseDBConnectionStringMySQL"];
var optionsBuilder = new DbContextOptionsBuilder<VerseDBContext>();
optionsBuilder.UseMySql(dbconn);
DbContextOptions<VerseDBContext> options = optionsBuilder.Options;
VerseDBContext x = new VerseDBContext(options);
services.AddSingleton<IVerseStorageReader>(new DBVerseReader(x));
But since DbContext derived classes are usually registered as scoped, I would suggest you move the context into the factory delegate and register the service abstraction as scoped also.
String dbconn = Configuration["ConnectionStrings:VerseDBConnectionStringMySQL"];
var optionsBuilder = new DbContextOptionsBuilder<VerseDBContext>();
optionsBuilder.UseMySql(dbconn);
DbContextOptions<VerseDBContext> options = optionsBuilder.Options;
services.AddScoped<IVerseStorageReader>( sp => {
VerseDBContext x = new VerseDBContext(options);
return new DBVerseReader(x);
});
In my data layer:
public interface IMyDataContext
{
IMyRepository MyRepository { get ; set ; }
// other repo's
}
public class MyDataContext : IMyDataContext
{
public MyDataContext ( string connectionKey)
{
ConnectionKey = connectionKey;
Database = new Database(ConnectionKey);
MyRepository = new MyRepository (ConnectionKey);
// other repo's
}
}
In my Web API service layer:
Configuring unity like so in my UnityConfig class:
_container = new UnityContainer();
_container.AddNewExtension<Interception>();
_container.RegisterType< IMyDataContext , MyDataContext >(
new ContainerControlledLifetimeManager(),
new Interceptor<InterfaceInterceptor >(),
new InjectionConstructor("MyConnectionKey" )
);
I wish to add behaviour for auditing to the MyRepository interface, something like this,
_container.RegisterType< IMyRespository, MyRepository >(
new Interceptor<InterfaceInterceptor >(),
new InterceptionBehavior<AuditingInterceptionBehaviour >()
);
only the AuditingInterceptionBehaviour never gets invoked if I do it this way. The only way to get it to invoke on that repo is to resolve in the constructor of my web api controller (below) but think this is not the best way to resolve it and was banking on auto resolving in the UnityConfig class.
public MyController( IMyDataContext datacontext)
{
_datacontext = datacontext;
_datacontext.MyRepository = UnityConfig.Instance.Resolve<IMyRespository> (new ParameterOverride("connectionKey", _datacontext.ConnectionKey));
}
If I add the behaviour to the registering of IMyDataContext, the AuditingInterceptionBehaviour class DOES GET invoked but I want to get method base properties for the calling repository (in my case IMyRepository) instead of its parent (IMyDataContext).
Can this be done in my UnityConfig class or do I need something more here?
Thought I'd post my answer on this:
Bascially, just needed to load the service layer unity container and resolve the repo in the data layer rather than in the Web API service layer like so:
public class MyDataContext : IMyDataContext
{
public MyDataContext ( string connectionKey)
{
ConnectionKey = connectionKey;
Database = new Database(ConnectionKey);
var container = new UnityContainer();
container.LoadConfiguration();
MyRepository = container.Resolve<IMyRespository>();
// resolve other repo's
}
}
I'm currently trying to do something that was dead simple and straight forward in ASP.NET 4 however this ins't the case now in ASP.NET 5.
Previously to use the UrlHelper it was dead simple:
var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
However I can't for the life of me wrap my head around how to use the new UrlHelper. I'm looking at the test cases and either I'm completely daft or I'm missing something and I can't seem to figure it out. Any help here in clearing up this would be great.
Update - Post RC2
As #deebo mentioned, you no longer can get an IUrlHelper directly from DI. Instead you need to inject an IUrlHelperFactory and an IActionContextAccessor into your class and use them to get the IUrlHelper instance as in:
public MyClass(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionAccessor)
{
this.urlHelperFactory = urlHelperFactory;
this.actionAccessor = actionAccessor;
}
public void SomeMethod()
{
var urlHelper = this.urlHelperFactory.GetUrlHelper(this.actionAccessor.ActionContext);
}
You need to also register the in your startup class (IUrlHelperFactory is already registered by default):
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
Bear in mind this will only work as long as the code where you get the actionContext is running after the MVC/routing middleware! (Otherwise actionAccessor.ActionContext would be null)
I have retrieved the IUrlHelper using the IServiceProvider in HttpContext.RequestServices.
Usually you will have an HttpContext property at hand:
In a controller action method you can do:
var urlHelper = this.Context.RequestServices.GetRequiredService<IUrlHelper>();
ViewBag.Url = urlHelper.Action("Contact", "Home", new { foo = 1 });
In a filter you can do:
public void OnActionExecuted(ActionExecutedContext context)
{
var urlHelper = context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var actionUrl = urlHelper.Action("Contact", "Home", new { foo = 1 });
//use actionUrl ...
}
Another option would be taking advantage of the built-in dependency injection, for example your controller could have a constructor like the following one and at runtime an IUrlHelper instance will be provided:
private IUrlHelper _urlHelper;
public HomeController(IUrlHelper urlHelper)
{
_urlHelper = urlHelper;
}
Thought I would share for the upcoming RC2 since the current answer won't work anymore then.
From RC 2 you will need to explicitly register IActionContextAccessor and IUrlHelperFactory
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
Then use the DI/service locator:
public EmailTagHelper(IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)
{
_urlHelper = urlHelperFactory.GetUrlHelper(actionContextAccessor.ActionContext);
}
I blogged about it here with regard to TagHelpers: http://devonburriss.me/asp-net-5-tips-urlhelper
In Startup.cs
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
services.AddScoped(it => it.GetService<IUrlHelperFactory>()
.GetUrlHelper(it.GetService<IActionContextAccessor>().ActionContext));
Alternatively
PM> Install-Package AspNetCore.IServiceCollection.AddIUrlHelper
In Startup.cs
services.AddUrlHelper();
If you just need the UrlHelper.Link method like I did, you don't even need the UrlHelper any more, just use Url.Link
A shorter version without constructing special Factory class
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddScoped<IUrlHelper>(sp => new UrlHelper(sp.GetRequiredService<IActionContextAccessor>().ActionContext));
I have a test where I pass in an object like so:
var repo = new ActualRepo();
var sut = new Sut(repo);
In my test, Repo has one method that I need to actually execute, whilst another method I want to mock out and not execute.
So for example, take this pseudocode:
var repo = new Mock<IRepo>();
repo.Setup(m => m.MethodIWantToCall()).WillBeExecuted();
repo.Setup(m => m.MethodIWantToMock()).Returns(false);
Using Moq, is this possible and how can it be done?
EDIT:
I've used TypeMock in the past and you can do something like.
Isolator.When(() => repo.MethodToIgnore()).WillBeIgnored();
Isolator.When(() => repo.MethodToActuallyRun()).WillBeExecuted();
Not too sure from the question if this is useful but it is possible to partially mock an object if the method that you want to mock is virtual.
public class Foo {
public string GetLive() {
return "Hello";
}
public virtual string GetMock() {
return "Hello";
}
}
public class Snafu {
private Foo _foo;
public Snafu(Foo foo) {
_foo = foo;
}
public string GetMessage() {
return string.Format("{0} {1}", _foo.GetLive(), _foo.GetMock());
}
}
[TestMethod]
public void NotMocked() {
var snafu = new Snafu(new Foo());
Assert.AreEqual("Hello Hello", snafu.GetMessage());
}
[TestMethod]
public void Mocked() {
var mockFoo = new Mock<Foo>();
mockFoo.Setup(mk => mk.GetMock()).Returns("World");
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetMessage());
}
You can't do this with Moq if you use the same object unless one of the method is virtual and you are basing your mock on a type rather than an interface.
That's because when you are passing a mock object based on an interface, you aren't passing a real object so it does not have access to the real methods of the object.
You are passing a dynamic proxy which will respond to methods it has been setup to respond to.
I believe TypeMock rewrites the assemblies at runtime to achieve this, something Moq definitively doesn't do.
If you want to achieve similar results with Moq:
You could mock both methods
You would have to extract both methods to different dependencies so as to mock one dependency and not the other.
You could have the method you need mocked be virtual, which would be the solution I would prefer.
EDIT : I edited my answer for correctness after reading AlanT's answer.
In my DAL, I'm currently using this in a base class:
protected static MyCMSEntities MyCMSDb
{
get { return new MyCMSEntities(ConfigurationManager.ConnectionStrings["MyCMSEntities"].ConnectionString); }
}
and calling like this from a subclass:
public static bool Add(ContentFAQ newContent)
{
MyCMSEntities db = MyCMSDb;
newContent.DateModified = DateTime.Now;
newContent.OwnerUserId = LoginManager.CurrentUser.Id;
db.ContentFAQ.AddObject(newContent);
return db.SaveChanges() > 0;
}
I understand the method to get the context is static, but as it creates a new intance of the context, this is not static, i.e. it is new for each call to the Add method.
Am I correct and more importantly, ok for a web application?
Thanks.
You are correct in using a new context for every web call - but why this obfuscation? I would recommend removing this indirection with the static property (makes the code harder to understand) and also using a using block since the context is disposable:
public static bool Add(ContentFAQ newContent)
{
using(var db = new MyCMSEntities())
{
newContent.DateModified = DateTime.Now;
newContent.OwnerUserId = LoginManager.CurrentUser.Id;
db.ContentFAQ.AddObject(newContent);
return db.SaveChanges() > 0;
}
}
Also the default constructor of the context should use the default connection string, which is the right one if you didn't change it in your configuration (otherwise just add it back in).