Initialize object with parameter by DI in asp core - c#

I have common DI usage in asp core application.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped(typeof(IUnitOfWork), typeof(UnitOfWork));//DAL
services.AddScoped(typeof(IUpService), typeof(UpService));//BLL
...
}
Controller get UpService by DI:
public BaseController(IUpService upService)
{
_upService = upService;
}
And in its turn BLL (upservice) get unitofwork instance:
public UpService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
In base controller i have property CurrentUser
public User CurrentUser
{
get
{
User user = null;
var tokenCookie = HttpContext.Request.Headers.FirstOrDefault(c => c.Key == "token");
if (!string.IsNullOrEmpty(tokenCookie.Value) && tokenCookie.Value != "undefined")
{
user = _upService.GetUserById(new Guid(tokenCookie.Value));
}
return user;
}
}
What i need is to pass CurrentUser to BL layer (to UpService). How to realise it by DI in asp core?
UPD:
Here the part of UpService, where i need current user.
public class UpService : IUpService
{
private IUnitOfWork _unitOfWork;
public User CurrentUser { get; set; }
public UpService(IUnitOfWork unitOfWork, IUserContext userContext)
{
_unitOfWork = unitOfWork;
//CurrentUser = userContext.CurrentUser;
}
public void Update(Document doc)
{
//here complex BL and then...
Document local;
var entity = _unitOfWork.DocumentsRepository.GetByID(doc.Id);
if (entity != null && HasChanges(local, entity))
{
entity.ChangedById = CurrentUser.Id;
_unitOfWork.Save();
}
}
public User GetUserById(Guid id)
{
return _unitOfWork.UserRepository.GetByID(id);
}
...

You should extract the CurrentUser into an abstraction, let's call it IUserContext. This abstraction can be implemented in your core layer. This way BL and DAL can access it. As part of your web application you create an implementation that adapts to ASP.NET Core and basically contains the logic that your CurrentUser property has. For instance:
public interface IUserContext
{
User CurrentUser { get; }
}
The adapter can look as follows:
public class AspNetUserContextAdapter : IUserContext
{
private readonly IHttpContextAccessor _accessor;
private readonly IUpService _upService;
public AspNetUserContextAdapter(IHttpContextAccessor accessor, IUpService _upService) {
_accessor = accessor;
_upService = upService;
}
public User CurrentUser
{
get
{
var context = _accessor.HttpContext;
var tokenCookie = context.Request.Headers.FirstOrDefault(c => c.Key == "token");
return !string.IsNullOrEmpty(tokenCookie.Value) && tokenCookie.Value != "undefined"
? _upService.GetUserById(new Guid(tokenCookie.Value))
: null;
}
}
}
This adapter can be registered as usual:
services.AddTransient<IUserContext, AspNetUserContextAdapter>();
On top of that, you might need to register ASP.NET Core's IHttpContextAccessor, since (in old versions of ASP.NET Core) it is not registered by default:
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Related

IHttpContextAccessor is null in class

I have problem when I'm trying to get httpcontext from IHttpContextAccessor field is always null in class.
There is my startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDistributedMemoryCache();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IUserContextServices, UserContextService>();
services.AddSession(options =>
{
options.Cookie.Name = ".AdventureWorks.Session";
options.IdleTimeout = TimeSpan.FromSeconds(10);
});
}
This is My UserContext Class which implements IUserContext interface
public class UserContextService : IUserContextServices
{
private readonly IHttpContextAccessor contextAccessor;
PQADBContext _context = new PQADBContext();
public UserContextService(IHttpContextAccessor accessor)
{
contextAccessor = accessor;
}
public UserContextService()
{
}
public HttpContext Context
{
get
{
return contextAccessor.HttpContext;
}
}
public int UserID()
{
return Context.Session.GetID("UserID").ConvertToInt();
}
public bool isLogin()
{
return Context.Session.GetBoolean("isLogin").ConvertToBool();
}
public UserAccount CreateSession(LoginViewModel logindata, bool EncryptPwd = true)
{
string error;
error = "";
try
{
string EncPwd = EncryptPwd ? EncryptDecryptHelper.Encrypt(logindata.Password) : logindata.Password;
var UserDetail =_context.UserAccount.Where(e => e.P_No == logindata.PNo && e.Password == EncPwd).SingleOrDefault();
if (UserDetail != null)
{
//HttpContext.Session.SetInt32()
// ///put all the properties in session variables
Context.Session.SetBoolean("isLogin", true);
Context.Session.SetID("UserID",UserDetail.AccountId);
Context.Session.SetID("P_No",Convert.ToInt32(UserDetail.P_No));
Context.Session.SetBoolean("isActive", true);
Context.Session.SetBoolean("Email", true);
Context.Session.SetID("RoleId", 1);
Context.Session.SetString("userName", "admin");
}
httpContext available in above class and also set the Session values but when i try to access httpcontext in this class it gives me null object reference
public class UserService
{
private readonly IHttpContextAccessor contextAccessor;
public IUserContextServices _userContext = new UserContextService();
public UserService()
{
}
public bool CreateEmployee(AppEmployees appemployee, int RoleId, bool isEmailSend, out string error)
{
appemployee.CreatedBy = _userContext.UserID(); //this line shows null reference exception
appemployee.CreatedDate = DateTime.Now;
}
You are newing up the UserContextService using the parameterless constructor
public IUserContextServices _userContext = new UserContextService();
instead of relying on Dependency Injection.
You need to configure your UserService to be used with your DI container - via constructor injection that would be
public class UserService
{
private readonly IUserServiceContext _userServiceContext;
public UserService(IUserServiceContext userServiceContext)
{
_userServiceContext = userServiceContext;
}
}
You will also need to amend your Startup.cs to register the UserService and you may want it to implement an interface too
Why do you use default constructor in your UserService?
You use next code:
public IUserContextServices _userContext = new UserContextService();
Of course here you have null for IHttpContextAccessor.
You need to use DI in your UserService.
Example:
private readonly IUserContextService _userContextService;
public UserService(IUserContextService userContextService)
{
_userContextService = userContextService;
}
There is good post about DI in .NET Core.
If you have set UserId directly as
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
}
This way you might get null UserId most of the time instead create httpContextAccessor field first like
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public string UserId { get { return httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); } }
Then get UserId, this way the problem of getting null UserId will be resolved.

IHttpContextAccessor null after injecting

I'm currently developing a system where dependent on what domain a request comes from different website settings need to be loaded (eg. default language id) which is then used in the rest of the application. These settings are stored in a class WebsiteSettings which are injected into the rest of the application when needed.
The first option I tried was registering a service to access the HttpContext by doing this in my ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
//Register other services
services.TryAddScoped<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddScoped<WebsiteSettingsFiller>();
services.TryAddScoped(typeof(WebsiteSettings), s =>
{
var settingFiller = s.GetService<WebsiteSettingsFiller>();
return settingFiller.Create();
});
}
Next, in my WebsiteSettingsFiller service, I inject the IHttpContextAccessor and some other services that I need to load the site settings.
public class WebsiteSettingsFiller
{
protected readonly IRepository Database;
private readonly IHttpContextAccessor _accessor;
private readonly StartupSitePropertyService _sitePropertyService;
private IQueryable<Site> AllSites => Database.All<Site>();
private IQueryable<SiteLanguage> AllSiteLanguages => Database.All<SiteLanguage>();
public WebsiteSettingsFiller(IRepository db, StartupSitePropertyService siteProperties, IHttpContextAccessor accessor)
{
Database = db;
_accessor = accessor;
_sitePropertyService = siteProperties;
}
public WebsiteSettings Create()
{
var domain = _accessor.HttpContext.Request.Host.Host; //null exception on this line
#if DEBUG
domain = "www.somewebsite.com";
#endif
var config = GetConfigByDomain(domain);
return config;
}
private WebsiteSettings GetConfigByDomain(string domain)
{
var site = AllSites.OrderByDescending(s => s.Created).FirstOrDefault(t => t.Host == domain);
if (site == null) return null;
var languages = AllSiteLanguages.Where(sl => sl.SiteId == site.Id).ToList();
//get more variables
return new WebsiteSettings
{
/* Set variables */
}
}
}
Example injection of WebsiteSettings:
public class RouteService : BaseService
{
private IDictionary<int, string> _routeLanguages = null;
private readonly WebsiteRedisService _websiteRedisService;
public RouteService(IRepository db,
WebsiteSettings settings,
WebsiteRedisService websiteRedisService)
: base(db, settings)
{
_websiteRedisService = websiteRedisService;
}
public async Task<IDictionary<int, string>> RouteLanguagesAsync()
{
return _routeLanguages ??
(_routeLanguages = await _websiteRedisService.SiteLanguagesToAsync(Settings.SiteId));
}
}
Sadly, no matter what I try the HttpContext reference is always null. Does anyone have any idea what I can try to resolve this? Or am I just approaching this problem the wrong way? Any suggestions are greatly appreciated!

Can't get Users with roles Asp.net MVC5 identity 2.2.1 dependency injection

Hello everybody!
After reading MRebati tip from my previous question, I searched and understod thanks to this blog the importance of not mixing unity and OWIN also how to dependency inject ASP.net identity.
So first of all I don't want to be marked as asking the same question even though I am, but now my code has changed a bit compare to the last question.
Anyway now I'm getting a different error message:
Object reference not set to an instance of an object.
Which means that I'm still getting null when calling my custom Usermanager.
My desired result is to get a list of all my users with their receptive roles :
XXXXXX ------ Admin
YYYYYY ------ Manager
Info about my project:
MVC: 5.2.3
Identity: 2.2.1
Entity framework : code first 2.2.1
Also I'm trying to use dependency injection with Unity.
Here's my code :
Controller :
public ActionResult GetUsersWithRoles(string roleName)
{
ViewBag.UsersWithRoles = _userManager.GetUsersInRole(context, roleName);
return View(ViewBag.UsersWithRoles);
}
My custom usermanager inside IdentityConfig.cs:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
/// the create part which is moved from the default ///
public IQueryable<ApplicationUser> GetUsersInRole(ApplicationDbContext context, string roleName)
{
if (context !=null && roleName !=null)
{
var roles = context.Roles.Where(r => r.Name == roleName);
if (roles.Any())
{
var roleId = roles.First().Id;
return from user in context.Users
where user.Roles.Any(r => r.RoleId == roleId)
select user;
}
}
return null;
}
Finally my view :
#using (Html.BeginForm("GetUsersWithRoles", "Roles"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<h3>Roles for this user </h3>
foreach (IQueryables in ViewBag.UsersWithRoles)
{
<tr>
<td>#s</td>
</tr>
}
}
Here's my unityConfig.cs
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using eCommerce.DAL.Repositories;
using eCommerce.Model;
using eCommerce.Contracts.Repositories;
using eCommerce.WebUI.Controllers;
using eCommerce.WebUI.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
namespace eCommerce.WebUI.App_Start
{
public class UnityConfig
{
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
#endregion
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IRepositoryBase<Customer>, CustomerRepository>();
container.RegisterType<IRepositoryBase<Product>, ProductRepository>();
container.RegisterType<IRepositoryBase<Basket>, BasketRepository>();
container.RegisterType<IRepositoryBase<Voucher>, VoucherRepository>();
container.RegisterType<IRepositoryBase<VoucherType>, VoucherTypeRepository>();
container.RegisterType<IRepositoryBase<BasketVoucher>, BasketVoucherRepository>();
container.RegisterType<IRepositoryBase<BasketItem>, BasketItemsRepository>();
//container.RegisterType<AccountController>(new InjectionConstructor());
container.RegisterType<ApplicationDbContext>(new PerRequestLifetimeManager());
container.RegisterType<ApplicationUserManager>();
container.RegisterType <IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new InjectionConstructor(typeof(ApplicationDbContext)));
}
}
}
Here's the constructor for the RolesController.cs :
private ApplicationDbContext context;
private ApplicationUserManager _userManager;
public RolesController(ApplicationDbContext context, ApplicationUserManager _userManager)
{
this.context = context;
this._userManager = _userManager;
}
Here's my startup.cs:
a
ssembly: OwinStartupAttribute(typeof(eCommerce.WebUI.Startup))]
namespace eCommerce.WebUI
{
public partial class Startup
{
internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>()); // <-
DataProtectionProvider = app.GetDataProtectionProvider();
}
}
}
Here's my Global.asax :
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AreaRegistration.RegisterAllAreas();
var context = new ApplicationDbContext();
if (!context.Users.Any(user => user.UserName == "Email#hotmail.com"))
{
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var applicationUser = new ApplicationUser() { UserName = "Email#hotmail.com" };
userManager.Create(applicationUser, "Password");
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
roleManager.Create(new IdentityRole("Admin"));
userManager.AddToRole(applicationUser.Id, "Admin");
}
}
}
Create method from my rolesController:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
context.Roles.Add(new IdentityRole
{
Name = collection["RoleName"]
});
context.SaveChanges();
ViewBag.ResultMessage = "Role created successfully !";
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Thank you for your time.
Better to keep the reference to DbContext in your UserManager:
public class ApplicationUserManager : UserManager<ApplicationUser>
{
private readonly ApplicationDbContext context;
public ApplicationUserManager(ApplicationDbContext context, /*... other parameters*/) : base(store)
{
this.context = context;
//... other configuration bits
}
public IEnumerable<ApplicationUser> GetUsersInRole(string roleName)
{
if (String.IsNullOrWhiteSpace(roleName))
{
throw new ArgumentNullException(nameof(roleName));
}
var role = context.Roles.FirstOrDefault(r => r.Name == roleName);
if (role == null)
{
throw new Exception($"Role with this name not found: {roleName}");
}
var users = context.Users.Where(u => u.Roles.Any(r => r.RoleId == role.Id)).ToList();
return users;
}
// the rest of User manager methods
}
In your controller avoid using ViewBag - it is just not a good practice. Also, as already been mentioned never pass IQueryable to your view. Roughly speaking IQueryable is a SQL query, but IEnumerable is a collection of objects. View needs to know only about objects. So your controller can look like this:
public class UsersWithRoleController : Controller
{
private readonly ApplicationUserManager userManager;
public UsersWithRoleController(ApplicationUserManager userManager)
{
this.userManager = userManager;
}
public ActionResult GetUsersWithRoles(string roleName)
{
var users = userManager.GetUsersInRole(roleName);
var viewModel = new GetUsersWithRolesViewModel()
{
RoleName = roleName,
Users = users,
};
return View(viewModel);
}
}
public class GetUsersWithRolesViewModel
{
public String RoleName { get; set; }
public IEnumerable<ApplicationUser> Users { get; set; }
}
And view will be:
#model IoCIdentity.Controllers.GetUsersWithRolesViewModel
#{
ViewBag.Title = "title";
}
<h2>List of users in role #Model.RoleName</h2>
<ul>
#foreach (var user in #Model.Users)
{
<li>#user.UserName</li>
}
</ul>
You can get the full sample in my github. Though I've not tested it properly - my db is broken at the moment -(

Get currently logged in user id in controller constructor ASP.NET 5 MVC6

In MVC5 I was initializing the ID of the currently logged in user to a private filed by overriding the Initialize method in the controller.
public class BaseControllerConstructor: Constructor
{
protected UserProfile _currentUserProfile;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
if (User.Identity.IsAuthenticated)
{
_currentUserId = User.Identity.GetUserId();
_currentUserProfile = LoadUserProfile(_currentUserId);
}
}
}
In MVC6 controllers do not have Initialize.
When I try to get the ID of the currently logged in user in the constructor, the User and the HttpContext are null.
public BaseControllerConstructor()
{
// HttpContext is null
string _currentUserId = HttpContext.User.GetUserId();
_currentUserProfile = LoadUserProfile(_currentUserId);
}
How can I achieve this in MVC6? Specifically: How can I get the user ID of the currently logged in user and initialize _currentUserId in the BaseControllerConstructor?
Then in the Controller action just call:
class Controller: BaseControllerConstructor
{
public ActionResult Action()
{
foo(_currentUserProfile);
}
}
Update: I solved this using dependency injection. Please, see my answer below.
I have solved this using dependency injection and IHttpContextAccessor class to access HttpContext.User.
Implement service which is registered as Startup.cs.
// The interface for the service.
public interface IAccountService
{
User CurrentUser { get; }
string CurrentUserId { get; }
}
// The class which implements the interface
public class AccountService : IAccountService
{
private IHttpContextAccessor _httpContextAccessor;
// This is a custom services which has access to the business model and the data model
private IUserService _userService;
private string _currentUserId;
private User _currentUser;
public AccountService(IHttpContextAccessor httpContextAccessor, IUserService currentUser)
{
_httpContextAccessor = httpContextAccessor;
_coreServiceProvider = coreServiceProvider;
_currentUserId = null;
_currentUser = null;
}
public User CurrentUser
{
get
{
if (_currentUser != null)
{
return _currentUser;
}
if (string.IsNullOrEmpty(_currentUserId))
{
// Get the user ID of the currently logged in user.
// using System.Security.Claims;
_currentUserId = _httpContextAccessor.HttpContext.User.GetUserId();
}
if (!string.IsNullOrEmpty(_currentUserId))
{
_currentUser = _userService.Find(_currentUserId);
if (_currentUser == null)
{
string errMsg = string.Format("User with id {0} is authenticated but no user record is found.", _currentUserId);
throw new Exception(errMsg);
}
}
return _currentUser;
}
}
public string CurrentUserId
{
get
{
if (!string.IsNullOrEmpty(_currentUserId))
{
return _currentUserId;
}
// Get the user ID of the currently logged in user.
// using System.Security.Claims;
_currentUserId = _httpContextAccessor.HttpContext.User.GetUserId();
return _currentUserId;
}
}
}
Register the services in class Startup method ConfigureServices
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
// Register UserService a custom class which has access to the user profiles
// This is injected.
services.AddScoped<IUserService, UserService>();
// Register the IAccountService which is injected in the controller
services.AddScoped<IAccountService, AccountService>();
}
}

ASP.NET MVC Post Authentication IoC setup

I have an http client wrapper that I'm injecting into all my controllers. If a user is authenticated, the injected wrapper should have some properties set with the authenticated user information.
I currently have this:
[System.Web.Mvc.Authorize]
public class ProfileController : Controller
{
private readonly IMyClient client;
public ProfileController()
{
string apiKey = ConfigurationManager.AppSettings["ApiKey"];
client = new MyClient(apiKey);
SetupClient();
}
private void SetupClient()
{
if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
{
var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
client.AddCredentials(tokenClaim.Value);
}
}
}
I would like to offload SetupClient to somewhere that will allow me to do dependency injection of IMyClient.
Essentially I want to implement this solution:
ProfileController.cs
[System.Web.Mvc.Authorize]
public class ProfileController : Controller
{
private readonly IMyClient client;
public ProfileController(IMyClient client)
{
this.client = client;
}
}
Startup.cs
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
IoCConfig.RegisterIoC(app);
ConfigureAuth(app);
}
}
IoCConfig.cs
public class IoCConfig
{
public static void RegisterIoC(IAppBuilder app)
{
var container = new Container();
container.Register<IMyClient>(
() =>
{
var apiKey = ConfigurationManager.AppSettings["APIKey"];
var myClient= new MyClient(apiKey);
// This will not work as this code is executed on app start
// The identity will not be of the user making the web request
var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
client.AddCredentials(tokenClaim.Value);
return myClient;
});
// Register the dependency resolver.
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
}
I'm stuck in the code for IoCConfig to extract information of the authenticated user (if the user is authenticated) and setup the client for injection. Any help here?
My IoC framework is SimpleInjector but I'd like an agnostic solution.
This is how I would do it
public class ProfileController : Controller
{
private readonly MyClient _client;
public ProfileController()
{
var clientInfo = Resolve<IClientInfo>(); // call out to your service locator
_client = clientInfo.GetClient();
}
}
public interface IClientInfo
{
MyClient GetClient();
}
public interface IAuth
{
System.Security.Claim GetSidClaim();
}
public class ClientInfo : IClientInfo
{
private readonly IAuth _auth;
public ClientInfo(IAuth auth)
{
_auth = auth;
}
public MyClient GetClient()
{
var apiKey = ApiKey;
var client = new MyClient(apiKey);
var claim = _auth.GetSidClaim();
client.AddCredentials(claim.Value);
return client;
}
protected virtual string ApiKey
{
get { return ConfigurationManager.AppSettings["APIKey"]; }
}
}
I'd take a look at NInject and the MVC extensions...
http://ninject.codeplex.com/wikipage?title=Dependency%20Injection%20With%20Ninject
http://www.codeproject.com/Articles/412383/Dependency-Injection-in-asp-net-mvc-and-webapi-us
When setup correctly it's just a matter of creating a binding for IMyClient NInject will implicitly inject it for you. There are lots of other injection frameworks out there, NInject is just the one I've chosen. Each of them will give you a substantial benefit over anything you could cook up on your own. e.g. with NInject you can create bindings that inject a singleton across your app or a binding that injects a singleton for each request.
In NInject you could create a binding something like
Bind<IMyClient>().ToMethod(x => SetupClient(x)).InRequestScope();
private IMyClient SetupClient(IContext context)
{
string apiKey = ConfigurationManager.AppSettings["ApiKey"];
var client = new MyClient(apiKey);
if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
{
var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
client.AddCredentials(tokenClaim.Value);
}
return client;
}
InRequestScope says that NInject should create a single instance for each request...
https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope
I think the equivalent in SimpleInjector is...
https://simpleinjector.codeplex.com/wikipage?title=ObjectLifestyleManagement#PerWebRequest
Is the answer as simple as changing your code to...
public static void RegisterIoC(IAppBuilder app)
{
var container = new Container();
container.RegisterPerWebRequest<IMyClient>(
() =>
{
...
I solved this by a version of what CRice posted by using a factory delegate:
ProfileController.cs
[System.Web.Mvc.Authorize]
public class ProfileController : Controller
{
private readonly IMyClient client;
public ProfileController(Func<IMyClient> clientFactory)
{
client = clientFactory.Invoke();
}
}
IoCConfig.cs
public class IoCConfig
{
public static void RegisterIoC(IAppBuilder app)
{
// Create the container as usual.
Container container = new Container();
// Registering as a factory delegate because we need the user authentication information if any.
container.RegisterSingle<Func<IMyClient>>(() =>
{
string apiKey = ConfigurationManager.AppSettings["ApiKey"];
var myClient = new MyClient(apiKey);
if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
{
var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
myClient.AddCredentials(tokenClaim.Value);
}
return myClient;
});
// This is an extension method from the integration package.
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
// This is an extension method from the integration package as well.
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
}

Categories

Resources