Multi-tenant logging in ASP.NET MVC application - asp.net

I have a multi-tenant application in ASP.NET MVC 5 that can accept client logins from multiple companies. Currently, I'm using log4net to log to files, but it places all the logs from all the companies in one file. Ideally, I would like to separate out the log files so that the logs for each company resides in its own folder.
I see from this question that I can programmatically create additional appenders, which then can log to different log files. But that would mean that for each instance of a class, I would have to keep calling
ILog log = LogManager.GetLogger("CompanyA");
to get the correct logger, right? Is there a better way to do so? I'm also open to using another logger if need be.
Thanks.

Do you use an Ioc container in your application? I was able to solve a similar problem using AutoFac MultitenantContainer. Steps that you need to follow
define the strategy you would use to identify each tenant.
Register a generic logger interface with Autofac container
For each tenant register specific logger.
your code could look like (extract from Autofac wiki)
var tenantIdStrategy = new RequestParameterTenantIdentificationStrategy("tenant");
var builder = new ContainerBuilder();
builder.RegisterType<BaseDependency>().As<IDependency>();
// If you have tenant-specific controllers in the same assembly as the
// application, you should register controllers individually.
builder.RegisterType<HomeController>();
// Create the multitenant container and the tenant overrides.
var mtc = new MultitenantContainer(tenantIdStrategy, builder.Build());
mtc.ConfigureTenant("CompanyA",
b =>
{
b.RegisterType<Tenant1Dependency>().As<IDependency>().InstancePerDependency();
b.RegisterType<Tenant1Controller>().As<HomeController>();
});
If this is the only instance where you need to differentiate the tenants and do not want to Ioc at this point you could create the factory like
static class LogFactory
{
public static ILog GetLogger()
{
var requestUri = HttpContext.Current.Request.Url.AbsoluteUri;
switch (requestUri)
{
case "companyA.domain.com":
return LogManager.GetLogger("CompanyA");
case "companyB.domain.com":
return LogManager.GetLogger("CompanyB");
default:
return LogManager.GetLogger("default");
}
}
}
now use the factory instead of directly using Logmanager
ILog logger = LogFactory.GetLogger();

Related

Autofac Multiple Regsistrations to Single service. Simple Injector -> Autofac translation

I've developed a CQRS style database access framework based on Tripod and other inspirations but targeting .NET Standard and simplifying for easier use. I want to split the IoC into separate integration packages so consumers can get the type registration I'm currently doing internally easily without being locked into a specific IoC container. My issue is I've only really worked closely with SimpleInjector so not familiar with other systems and their nuances around how they handle specific scenarios. I have an iminent need to support Autofac so thought I'd try here to see if anyone can translate.
I have the following Simple Injector CompositionRoot static class:
public static void RegisterDatabase(this Container container, DbContextOptions<EntityDbContext> dbContextOptions, params Assembly[] assemblies)
{
var scopedLifeStyle = container.Options.DefaultScopedLifestyle;
//container.Register<ICreateDbModel, DefaultDbModelCreator>(scopedLifeStyle); // lifestyle c
container.RegisterInitializer<EntityDbContext>( //(container.InjectProperties);
handlerToInitialise => handlerToInitialise.ModelCreator = new DefaultDbModelCreator()
);
// Setup DbContext
var ctxReg = scopedLifeStyle.CreateRegistration(
() => new EntityDbContext(dbContextOptions),
container);
container.AddRegistration<IUnitOfWork>(ctxReg);
container.AddRegistration<IReadEntities>(ctxReg);
container.AddRegistration<IWriteEntities>(ctxReg);
}
In ASP.NET Core solutions I invoke the above from Startup.Configure(...) with:
var optionsBuilder = new DbContextOptionsBuilder<EntityDbContext>()
//.UseInMemoryDatabase("Snoogans");
.UseSqlServer(_config.GetConnectionString("DefaultConnection"));
container.RegisterDatabase(optionsBuilder.Options);
which allows me to switch out to an in memory database for unit testing if needed. EntityDbContext contains all my unit of work methods for calling onto the context without having to specify explicit DbSet for each table. The IUnitOfWork, IReadEntities and IWriteEntities interfaces all define methods on the EntityDbContext.
So I'm not sure how I'd go about making an Autofac module that allows scoped registration of the dbcontext with passed in DbContextOptions followed by multiple registrations of interfaces to this registration.
Does anyone know how this can be achieved?
I worked out the process and now have an AutoFac module. I was able to registermodule by instance of the class and also pass in the options when I instantiate. Because EntityDbContext implements the three interfaces I was registering separately in the Simple Injector scenario, AutoFac has the convenience of being able to just infer them and register with AsImplementedInterfaces()
public class EntityFrameworkModule : Module
{
private readonly DbContextOptions<EntityDbContext> _dbContextOptions;
public EntityFrameworkModule(DbContextOptions<EntityDbContext> dbContextOptions)
{
_dbContextOptions = dbContextOptions;
}
protected override void Load(ContainerBuilder builder)
{
// If the calling code hasn't already registered a custom
// ICreateDbModel then register the internal DefaultDbModelCreator
builder.RegisterType<DefaultDbModelCreator>()
.IfNotRegistered(typeof(ICreateDbModel))
.As<ICreateDbModel>();
// Expecting IUnitOfWork, IReadEntities and IWriteEntities to be registered with this call
builder.Register(c => new EntityDbContext(_dbContextOptions)
{
ModelCreator = c.Resolve<ICreateDbModel>()
})
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}

ASP.NET Core Identity - UserManager and UserStore woes

I'm trying to implement the Identity system in an ASP.NET Core app (RC2 libraries) and there is a particular hangup that is driving me crazy.
First of all, I am not using EntityFramework. I'm not even using SQL. I'm backing up to RavenDB, so I need the implementation to be very specific to that; Which isn't a problem.
So I designed a RavenUserStore class, and it looks like this;
public class RavenUserStore<TUser> :
IUserStore<TUser>,
IUserLoginStore<TUser>,
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserClaimStore<TUser>,
IUserLockoutStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserEmailStore<TUser> {
// ...
}
Works great on its own. I've implemented all the methods, etc. It's wonderful. Very clean and efficient.
Now, I go over to my web application and wire things up;
services.AddTransient<ILookupNormalizer>(s => new LowerInvariantLookupNormalizer());
services.AddTransient<IPasswordHasher<Member>>(s => new PasswordHasher<Member>());
services.AddTransient<IUserStore<Member>, RavenUserStore<Member>>();
services.AddIdentity<Member, Role>(o => {
o.Password.RequiredLength = 6;
o.Password.RequireDigit = true;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
})
.AddUserStore<RavenUserStore<Member>>()
.AddRoleStore<RavenRoleStore<Role>>();
So I go make a controller to use this, per all the samples I've seen, and the very core sample from the Identity Framework Github Repository
//... [PROPERTIES]...//
public AccountController(UserManager<Member> userManager, SignInManager<Member> signInManager) {
// ... [attach constructor parameters to properties] ...//
}
Alright, so I inspect the classes carefully.
UserManager<T> has a property Store,which is a type of IUserStore<T>.
So theoretically.. if the dependency injection resolves types of IUserStore<T> to RavenUserStore<T> when they are injected through a constructor.. shouldn't that mean that the UserManager<T> gets a RavenUserStore<T> as its Store property?
I thought it would too; But when I call methods on the UserManager, it DOES NOT call the ones on my RavenUserStore. Why is this? What can I do?
Do I really have to ALSO make a custom UserManager class and do all of those methods AGAIN?
You need to add your own custom providers before calling services.AddIdentity(). Internally, AddIdentity uses TryAddScoped() which only adds the default items if they don't already exist in the services container.
So just putting the call to AddIdentity() after you registered all your custom implementations should mean that they will take precedence as you expect.

When ApplicationID is generated in Membership.CreateUser method?

I was working with ASP.Net Membership and was wondering when exactly ApplicationID is generated. I want to know what events are called and when does ApplicationID is generated when we use "Membership.CreateUser" method.
I googled it for some time but couldn't find any satisfactory answer.
Can anyone explain what is the working of this method?
Thanks
I want to know what events are called and when does ApplicationID is
generated when we use "Membership.CreateUser" method.
Right before processing any request to Membership table (such as select/insert/update/delete), Application is retrieved by applicationName.
For example, inside the Membership.CreateUser method, QueryHelper.GetApplication is called right before creating a new user.
Application application = QueryHelper.GetApplication(membershipEntity,
applicationName);
// QueryHelper.GetApplication
internal static Application GetApplication(MembershipEntities ctx,
string applicationName)
{
ObjectParameter[] objectParameter = new ObjectParameter[1];
objectParameter[0] = new ObjectParameter("name",
applicationName.ToLowerInvariant());
Application application = ctx.CreateQuery<Application>(
"select value a FROM Applications as a WHERE ToLower(a.ApplicationName) = #name",
objectParameter).FirstOrDefault<Application>();
return application;
}
If application is null, it is created an application like this -
internal static Application CreateApplication(MembershipEntities ctx,
string appName)
{
Application application = new Application();
application.ApplicationId = Guid.NewGuid();
application.ApplicationName = appName;
ctx.Applications.AddObject(application);
Application application1 = application;
return application1;
}
About code is from ASP.NET Universal Providers. Legacy Membership Provider uses Store Procedure, but the logic is almost same.

Controller reuse in asp.net mvc

I have a two different projects that are actually two different websites when deployed, say WebA & WebB. The structure of both websites is the same in terms of the controllers and models they use. However, the front end is very different. They each have their own UI and own jquery plugins that work for them.
To reduce code duplication, I am proposing both those projects inherit from controllers in another referenced project[controllerDLL]. ControllerDLL is a project that will have all the logic for calling the business layer and returning json serialized model objects. WebA & WebB will each just have empty controller classes that just inherit from the base project[controllerDLL]. This way I feel the controller code is not duplicated.
Can anyone tell me a better way to achieve controller reuse other than the way I have proposed? Does asp.net mvc 4 provide any built-in way to do this better? Can I use AREAS here productively? Is DotNetNuke something I should look at? Or is my approach the best way forward? I am not looking for the how to move controllers into another project. I just want to know what my options are for achieving controller reuse.
Thanks.
Take a look at this SO question. You could keep all the views in the same project and use a custom view engine to find the views (based off a web.config setting).
For example you could have 2 folders /Views/WebA and /Views/WebB. The custom view engine could look up the web.config setting to find out which folder to use and search for the views there. This way you would not have to duplicate the controller code or move it into a separate project. It will just swap out one presentation layer for another at runtime.
You should be able to achieve this by implementing custom controller factory to instantiate the right controller class based on config settings.
You need to implement the interface System.Web.Mvc.IControllerFactory.The two methods in this interface are:
1.System.Web.Mvc.IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) - To create the controller instance based on RequestContext and controller name.
2.void ReleaseController(System.Web.Mvc.IController controller) - Release the controller instance
Detailed information about using that interface is available
Since the difference between the two applications are the views, you don't need to have them as separate projects. you could have two sets of views and deploy the same project twice using different settings in the web config. To do this, you'll have to implement your own ViewEngine so that the controller can return the correct right views.
public class AppSettingViewEngine: RazorViewEngine
{
public AppSettingViewEngine()
{
string[] viewLocations = new string[] { };
if (ConfigurationManager.AppSettings["Site"] == "WebA")
{
viewLocations = new[] {
"~/WebB/Views/{1}/{0}.cshtml",
"~/WebB/Views/{1}/{0}.cshtml",
"~/WebB/Views/Shared/{0}.cshtml",
"~/WebB/Views/Shared/{0}.cshtml",
};
}
if (ConfigurationManager.AppSettings["Site"] == "WebB")
{
viewLocations = new[] {
"~/WebB/Views/{1}/{0}.cshtml",
"~/WebB/Views/{1}/{0}.cshtml",
"~/WebB/Views/Shared/{0}.cshtml",
"~/WebB/Views/Shared/{0}.cshtml",
};
}
else
{
//Default Settings
viewLocations = new[] {
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
};
}
this.PartialViewLocationFormats = viewLocations;
this.ViewLocationFormats = viewLocations;
}
}
Then you register it in your Application_Start as follows
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new AppSettingViewEngine());
}

Unity ServiceLocator, register types at runtime

I have a small toolkit which uses Unity DI plus EntLib Service Locator. The problem appears when a third party apps try to use the EntLib service locator. It looks like the EntLib Service Locator is singleton so when the third party app bootstrap its service locator, it wipes out the configuration of my service locator.
The client creates the Service Locator in this way:
container = new UnityContainer();
locator = new UnityServiceLocator(Initialize());
ServiceLocator.SetLocatorProvider(() => locator);
And it is used in this way:
ServiceLocator.Current.GetInstance<IService>("MyService");
Is there any way to manage two ServiceLocator or to register additional components in the service locator at runtime?
Since Unity container is registered within itself, you could get it and configure:
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
// do what you want with container
The only feasible solution I have found is to get the current IUnityContainer configured for the ServiceLocator and recycle it.
In order to do that I used reflection in this way:
var locator = (UnityServiceLocator) ServiceLocator.Current;
var field = locator.GetType().GetField("container", BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null)
{
var iocContainer = field.GetValue(ServiceLocator.Current) as IUnityContainer;
if (iocContainer != null)
{
ConfigureContainer(iocContainer);
}
}

Resources