This question already has an answer here:
Mock HttpRequest in ASP.NET Core Controller
(1 answer)
Closed 4 years ago.
I'm having the following setup:
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller
{
public UserDetails UserDetails => Request.GetUserDetailsFromHttpHeaders();
}
public class ExampleConcreteController : ExampleBaseController
{
// UserDetails is being used in here
// this is the class under test
I need to be able to inject UserDetails during production run and also be able to mock it during tests.
Since UserDetails depends on Request and Request is a member of Microsoft.AspNetCore.Mvc.Controller I do not know how to achieve this.
If you want to mock something, you should first allow mocking on it. If you want to mock UserDetails you should allow mocking on its getter and pass required context inside newly crafted contract:
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly IUserDetailsProvider _userDetailsProvider;
public UserDetails UserDetails => _userDetailsProvider.Get(Request);
public ExampleBaseController(IUserDetailsProvider userDetailsProvider)
{
_userDetailsProvider = userDetailsProvider;
}
}
So, in test you mock IUserDetailsProvider to return some "foobar". In production you just invoking GetUserDetailsFromHttpHeaders() method on passed inside Request.
To answer question about Request and Controller relations. Controller depends on Request, yes, and Microsoft thought that it will be good to strongly merge them together instead of passing dependency, for example like this:
public class FooBarController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly System.Web.HttpRequestBase _request;
public FooBarController(System.Web.HttpRequestBase request)
{
_request = request;
}
}
Or even like this:
public class FooBarController : Microsoft.AspNetCore.Mvc.Controller
{
public void ProcessRequest(System.Web.HttpRequestBase request)
{
//request here
}
}
They instead used Property injection, which leaves developer with no way to affect injection. This is a problem. But not unsolvable - you just pass context inside (by delegate, by interface, by reference), if you need one of those coupled together objects.
It could be not so convinient as solution, proposed by #eocron, but still:
public interface IWithUserDetails
{
UserDetails UserDetails();
}
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller, IWithUserDetails
{
public UserDetails UserDetails()
{
return Request.GetUserDetailsFromHttpHeaders();
}
}
Same name for class and method is not a best way to do, but it was like it in the example with a property
Here is another point of view:
public interface IUserDetailsProviderOptions
{
Func<UserDetails> UserDetailsProvider { get; set; }
}
public class DefaultUserDetailsProviderOptions : IUserDetailsProviderOptions
{
public Func<UserDetails> UserDetailsProvider {get; set;}
}
public class ExampleBaseController : Microsoft.AspNetCore.Mvc.Controller
{
private readonly Func<UserDetails> _userDetailsProvider;
public UserDetails UserDetails => _userDetailsProvider();
public ExampleBaseController(IUserDetailsProviderOptions options)
{
_userDetailsProvider = options.UserDetailsProvider ??
Request.GetUserDetailsFromHttpHeaders;
}
}
Register in Startup.cs like this:
services.AddSingleton<IUserDetailsProviderOptions, DefaultUserDetailsProviderOptions>();
In testing you could do:
public class StubUserDetailsOption : IUserDetailsProviderOptions
{
public Func<UserDetails> UserDetailsProvider { get; set; } = () => new StubDetails();
}
var controller = new ExampleBaseController(new StubUserDetailsOption());
and do testing.
Related
I have a user class hierarchy a follows:
public class BaseUser
{
public virtual UserTask()
{
// Some Code
}
}
public class SubUser1 : BaseUser
{
public override UserTask()
{
// Some Code
}
}
public class SubUser2 : SubUser1
{
public override UserTask()
{
// Some Code
}
}
And there is a class with constructor using dependency injection as follows:
public class UserManagement
{
public UserManagement(BaseUser user)
{
// Some code
}
}
I am working on Asp.Net Web API, in which a controller use this class UserManagement.
My problem is how to get object of SubUser1 and SubUser2 in UserManagement constructor.
I am new to Dependency Injection.
Please suggest any solution or article which guide me to achieve this.
Any help would be appreciated.
Below is a simple but functional example of roughly how I would do Dependency Injection. This works great when my DbContext connection string is not dynamic. Even if it's passed in to the factory through a config file or whatever, it doesn't matter so long as it's the same one all the time.
What I need is to wrap my head around how to make (ideally minor) modifications to the below code to allow for the connection string to be determined dynamically at run time.
For example, say on the View the user was able to not only select the teacher to be passed into the Post method of the controller, but also the school. If, for simplicity sake, there are 2 schools that have the exact same database structure, but have different connection strings how do I get that down from the controller to the factory?
I've experimented with passing a value from method to method, but this isn't really sustainable for large projects, increases the likelihood of errors and overall is just messy (besides violations of SOLID) to be passing something from layer to layer like that. (If desired I can add the not exactly ideal attempts I've made, I've omitted them for brevity sake since this is already a fairly long question what with the code examples and all).
Controller
public class HomeController : Controller
{
private readonly IDataService _dataService;
public HomeController(IDataService dataService)
{
_dataService = dataService;
}
public ActionResult Index()
{
var results = _dataService.GetTeachers();
var model = new ViewModel
{
Teachers = results
};
return View(model);
}
[HttpPost]
public ActionResult Index(ViewModel model)
{
var results = _dataService.GetCourses(model.Teacher);
model.Courses = new List<string>(results);
return View(model);
}
}
Service
public class DataService : IDataService
{
private readonly IDataRepo _dataRepo;
public DataService(IDataRepo dataRepo)
{
_dataRepo = dataRepo;
}
public List<string> GetCourses(string teacherName)
{
return _dataRepo.GetCourses()
.Where(c => c.Teacher.FirstName == teacherName)
.Select(c => c.Name)
.ToList();
}
public List<string> GetTeachers()
{
return _dataRepo.GetCourses()
.Select(c => c.Teacher.FirstName)
.ToList();
}
}
Repository
public class DataRepo : IDataRepo
{
private readonly SchoolContext _context;
public DataRepo()
{
_context = ContextFactory.MakeContext();
}
public IEnumerable<Course> GetCourses()
{
return _context.Courses;
}
}
Context Factory
public static class ContextFactory
{
public static SchoolContext MakeContext()
{
var connString =
"connStringA";
return new SchoolContext(connString);
}
}
UnityConfig
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IDataService, DataService>();
container.RegisterType<IDataRepo, DataRepo>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
First, you have to decide how are you going to get the current connection string to use. Is it through a URL? or using the current user or whatever other way.
Then, create another database that has a mapping between the connection strings and the method you chose (user, url ...)
Lastly, implement a way to get the record from the database.
so, assuming that you will use the URL as an identifier for the current tenant, your entity class should be like this:
public class Tenant
{
public string Url {get;set;}
public string ConnectionString {get;set;}
}
An interface that represents the logic to get the current tenant:
public interface ICurrentTenantService
{
Tenant GetCurrentTenant();
}
And now you will put its implementation
public class CurrentTenantService : ICurrentTenantService
{
public Tenant GetCurrentTenant()
{
string currentUrl = HttpContext.Current.Url; //make sure to get only the base URL here
return TenantDbContext.Tenants.FirstOrDefault(t=>t.Url == url); //TenantDbContext should be a class that has the Tenant entity
}
}
Now you have to wire up the context factory to the tenant service like this
public static class ContextFactory
{
private readonly ICurrentTenantService currentTenantService;
//Inject it in the constructor
public static SchoolContext MakeContext()
{
var currentTenant= currentTenantService.GetCurrentTenant(); //Check for NULL
return new SchoolContext(currentTenant.ConnectionString);
}
}
I have a set of interfaces I need to implement, and in each implementation I need to access a value that is available in the calling context, but is not a part of the interface method. Also, the calling context receives the instance as a dependency.
To solve this, I'm looking to see if there is some way to create a scoped context of sorts, similar to HttpContext, with a limited lifespan.
This is how I envision it: The OrderProcessor class makes the userId value available to all method calls within the using scope for the instance of the UserContext class.
The question is: Is this even possible, and if so how?
public class OrderProcessor
{
private readonly IBusiness _business;
public OrderProcessor(IBusiness business)
{
_business = business; // DI is providing us with an instance of MrBusiness
}
public static void ProcessOrders(string userId)
{
using (new UserContext(userId))
{
var thisUsersOrders = _business.GetOrders();
}
}
}
public interface IBusiness
{
List<Order> GetOrders();
}
public class MrBusiness : IBusiness
{
public List<Order> GetOrders()
{
var userId = UserContextManager.Current.UserId;
// Use the userId to retrieve data from somewhere
}
}
public class UserContextManager
{
public static UserContext Current
{
get
{
// If this had been a web application I could perhaps have used the Http context, hmm?
}
}
}
public class UserContext : IDisposable
{
public string UserId { get; }
public UserContext(string userId)
{
UserId = userId;
}
public void Dispose()
{
}
}
My controller which returns user details by calling an API intern
public class HomeController : Controller
{
public ActionResult AccountDetails(int userId)
{
return this.Content(new WebHelperService().GetAccountDetails(userId)), "application/json");
}
}
Here is my WebHelperService which is in Business Layer, where i need to get value from appsettings.json
public class WebHelperService
{
private string url = null;
public WebHelperService()
{
//url = ConfigurationManager.ConnectionString["ExternalApiUrl"].ToString();
// ConfigurationManager is not available in .net core.
//So How do i read ExternalApiUrl from appsettings.josn,Which is the best way
}
public string GetAccountDetails(int userId)
{
return WebCall("{'userId':" + userId + "}");
}
private string WebCall(string data)
{
WebRequest request = WebRequest.Create(url);
// get the data from url and returns it
}
}
Do I need to carry settings all the way from controller in mvc6?
Reference : learn.microsoft.com/en-us/aspnet/core/mvc/con..)
Let's forget for a moment your particular use case and just talk about settings in .net core in general. Importantly, I think you are trying to access the raw AppSettings from your class, but what you actually want to do is DI them into your class. So let's do that.
Consider you have a appSettings.json that resembles something like below :
{
"myConfiguration": {
"myProperty": true
}
}
Now you need to create a POCO to hold these settings. Something like so :
public class MyConfiguration
{
public bool MyProperty { get; set; }
}
In your startup.cs you should have a method called "ConfigureServices". In there you are going to place a call to "configure" your settings like so.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration"));
}
And so now you want to inject that settings object into a class. Let's call it MyClass for now. It would look like the following :
public class MyClass : IMyClass
{
private readonly MyConfiguration _myConfiguration;
public MyClass(IOptions<MyConfiguration> myConfiguration)
{
_myConfiguration = myConfiguration.Value;
}
}
Now you have access to your configuration!
Bonus!
Instead you can make your ConfigureServices method look like the following :
public void ConfigureServices(IServiceCollection services)
{
//services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration"));
services.AddSingleton(Configuration.GetSection("myConfiguration").Get<MyConfiguration>());
}
What this now does is bind your services onto an actual class, not the IOptions object.
Now when you inject it into your class, you instead inject the POCO settings class, not IOptions. Like so :
public class MyClass : IMyClass
{
private readonly MyConfiguration _myConfiguration;
public MyClass(MyConfiguration myConfiguration)
{
_myConfiguration = myConfiguration;
}
}
For further reading :
http://dotnetcoretutorials.com/2016/12/26/custom-configuration-sections-asp-net-core/
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration
I'm having a little trouble wrapping my head around the Ninject Factory Extension.
I have the following class structure
public class Resource
{
public IResourceLoader ResourceLoader {get;set;}
public Resource(IResourceLoader ResourceLoader)
{
this.ResourceLoader = ResourceLoader ;
}
}
public class Banner : Resource
{
public Banner([Named("pngLoader")] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named("xmlLoader") IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
interface IResourceLoader
{
object resource {get;}
}
public class XMLLoader : IResourceLoader
{
public resource { return "this was sent by xml loader"; }
}
public class PNGLoader : IResourceLoader
{
public resource { return "this was sent by png loader"; }
}
I'm trying to implement convention based filtering based on the Named attribute as show here. So I implemented the following interface.
interface IResourceLoaderFactory
{
IResourceLoader GetxmlLoader();
IResourceLoader GetpngLoader()
}
And then my bindings in the dependency resolver look like
kernel.Bind<IResourceLoader>().To<XMLLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetxmlLoader());
kernel.Bind<IResourceLoader>().To<PNGLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetpngLoader());
Assuming the above is correct, I don't know how to proceed to have it so that Ninject gives Banner or MetaData the correct IResourceLoader based on the [Named] in the constructor that it passes it to the base constructor.
I'm using all of this in an mvc 5 application like
public class HomeController
{
public ActionResult Index(/* do banners and meta need to be asked for here? */)
{
/* or do I need to instantiate them here/? */
Banner banner = new Banner(/* what to put here? */);
Meta meta = new Meta(/* what to put here? */);
...
}
}
Thanks
Let me try to answer your question, i'm not a 100% sure i've understand your question correctly, so please give me feedback if i haven't.
Now, your basic problem is that you want to inject an IResourceLoader - but depending on what you inject it into, it should either be an XMLLoader or a PNGLoader.
You've correctly identified named bindings as one possible solution for choosing the appropriate IResourceLoader.
However, you don't need to combine NamedLikeFactory and [Named]-Attribute pattern to achieve what you want, one of those is enough, and here the [Named]-Attribute is probably the better alternative of the two (there is a third which i'll get to later).
So here's what you do:
public const string XmlLoaderName = "XmlLoader";
public const string PngLoaderName = "PngLoader";
Bind<IResourceLoader>().To<XMLLoader>()
.Named(XmlLoaderName);
Bind<IResourceLoader>().To<PNGLoader>()
.Named(PngLoaderName);
And then you specify the appropriate type in the ctor (as you did):
public class Banner : Resource
{
public Banner([Named(pngLoaderName)] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named(xmlLoaderName) IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
and that's basically it!
now to use it in your controller all you've got to do is:
public class HomeController
{
public HomeController(Banner baner, MetaData metaData)
{
...
}
}
no need to use a factory. Except, in case you need to instantiate a Banner orMetaData instance per request, in which case you would create a factory interface:
public interface IResourceFactory
{
Banner CreateBanner();
MetaData CreateMetaData();
}
which is bound like:
Bind<IResourceFactory>().ToFactory();
// ToFactory is an extension method from Ninject.Extensions.Factory
which will be used like:
public class HomeController
{
private readonly IResourceFactory resourceFactory;
public HomeController(IResourceFactory resourceFactory)
{
this.resourceFactory = resourceFactory;
}
public ActionResult Index()
{
var banner = this.resourceFactory.CreateBanner();
....
}
}
Alternative for Named binding: You could also use a conditional binding like:
Bind<IResourceLoader>().To<XMLLoader>()
.WhenInjectedInto<Banner>();
and corresponding Banner ctor:
public Banner(IResourceLoader resourceLoader)
{
...
}
This alternative can make sense if there's a very limited set of classes which get a ResourceLoader injected. Or if you can't add an [Named]-Attribute to the ctor (for example because it's a third party library...).
Another alternative altogether again would be to give Ninject more information on how to construct a type. For Example:
Bind<Banner>().ToSelf()
.WithConstructorArgument(
typeof(IResourceLoader),
ctx => ctx.Kernel.Get<XmlLoader>());