Basically I'm trying to create a SessionManager class which I can use to manage sessions in my MVC applications. For that I'm thinking the best way of doing so is by creating a wrapper class for HttpContext which would then allow me to access HttpContext.Current.Session.
To be honest, I'm not really sure about the whole thing, I just feel it's the logical way of doing so. I also want to create an ISessionManager and ISession interfaces, and then implement them according to my application's needs. For my current project, and for now, I need a InProc session management, but I might need to store session data in MSSQL Server when we decide to expand and use a web farm or a garden. That's why I'm trying to build a sort of an extensible framework right from the start.
Final note, I will be using Microsoft Unity to inject the concrete SessionManager of choice. I believe that's a good way to maintain a certain level of abstraction.
Any suggestions for achieving all that?
Thanks in advance! :)
Ok here's what I came up with, but I'm not sure that's the right way of doing this so your opinions are most welcome!
ISessionManager:
public interface ISessionManager
{
void RegisterSession(string key, object obj);
void FreeSession(string key);
}
SessionManager:
public class SessionManager : ISessionManager
{
private IDictionary<string, object> sessionDictionary;
public SessionManager(IDictionary<string, object> _sessionDictionary)
{
sessionDictionary = _sessionDictionary;
}
public IDictionary<string, object> Session
{
get
{
return sessionDictionary;
}
}
public void RegisterSession(string key, object obj)
{
sessionDictionary[key] = obj;
}
public void FreeSession(string key)
{
sessionDictionary[key] = null;
}
}
Then when I want to instantiate the class (inside my web app), I would do something like that:
var sessionManager = new SessionManager(HttpContext.Current.Session);
sessionManager.RegisterSession["myKey"] = someObject;
But I would prefer to avoid using magic strings as the key. I could include a constant string property like sessionKey = "myKey" in the class, but that would mean I could only store one object in the session manager, right?
Feedback please. :)
Related
I'm looking into asp.net core and the new security policies and claims functionality. Having just looked at it I don't see how it is much better than the existing authorize attribute logic in the past where hard-coded roles or users are decorated on controllers, methods etc. To me the issues has just been moved from hard-coding in attributes to hard-coding policies.
Ideally I would like to perform activity/resource based authorization where everything would be database driven. Each activity or resource would be stored in the database and a permission/role would be assigned to the resource.
While researching the topic I found this fantastic article by Stefan Wloch that pretty much covers exactly what I'm looking to do.
http://www.codeproject.com/Articles/1079552/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NE
So my question is with the new core features how does it prevent us from having to hard-code and recompile when the time comes to change what roles/permissions are allowed to access a controller or method in a controller? I understand how claims can be used to store anything but the policy portion seems susceptible to change, which gets us back to square one. Don't get me wrong, loving asp.net core and all the great changes, just looking for more information on how to handle authorization.
There are at least 2 things that need to be consider in implementing what you want. The first one is how to model the Controller-Action access in database, the second one is to apply that setting in asp.net core Identity.
The first one, there are too many possibilities depend on the application itself, so lets create a Service interface named IActivityAccessService that encapsulate. We use that service via dependency injection so that anything that we need can be injected to it.
As for the second one, it can be achieved by customize AuthorizationHandler in a policy-based authorization. The first step is to setup things in Startup.ConfigureServices :
services.AddAuthorization(options =>
{
options.AddPolicy("ActivityAccess", policy => policy.Requirements.Add( new ActivityAccessRequirement() ));
});
services.AddScoped<IAuthorizationHandler, ActivityAccessHandler>();
//inject the service also
services.AddScoped<IActivityAccessService, ActivityAccessService>();
//code below will be explained later
services.AddHttpContextAccessor();
next we create the ActivityAccessHandler:
public class ActivityAccessHandler : AuthorizationHandler<ActivityAccessRequirement>
{
readonly IActivityAccessService _ActivityAccessService;
public ActivityAccessHandler (IActivityAccessService r)
{
_ActivityAccessService = r;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authHandlerContext, ActivityAccessRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext filterContext)
{
var area = (filterContext.RouteData.Values["area"] as string)?.ToLower();
var controller = (filterContext.RouteData.Values["controller"] as string)?.ToLower();
var action = (filterContext.RouteData.Values["action"] as string)?.ToLower();
var id = (filterContext.RouteData.Values["id"] as string)?.ToLower();
if (_ActivityAccessService.IsAuthorize(area, controller, action, id))
{
context.Succeed(requirement);
}
}
}
}
public class ActivityAccessRequirement : IAuthorizationRequirement
{
//since we handle the authorization in our service, we can leave this empty
}
Since we can use dependency injection in AuthorizationHandler, it is here that we inject the IActivityAccessService.
Now that we have access to what resource is being requested, we need to know who is requesting it. This can be done by injecting IHttpContextAccessor. Thus services.AddHttpContextAccessor() is added in code above, it is for this reason.
And for the IActivityAccessService, you could do something like:
public class ActivityAccessService : IActivityAccessService
{
readonly AppDbContext _context;
readonly IConfiguration _config;
readonly IHttpContextAccessor _accessor;
readonly UserManager<AppUser> _userManager;
public class ActivityAccessService(AppDbContext d, IConfiguration c, IHttpContextAccessor a, UserManager<AppUser> u)
{
_context = d;
_config = c;
_accessor = a;
_userManager = u;
}
public bool IsAuthorize(string area, string controller, string action, string id)
{
//get the user object from the ClaimPrincipals
var appUser = await _userManager.GetUserAsync(_accessor.HttpContext.User);
//get user roles if necessary
var userRoles = await _userManager.GetRolesAsync(appUser);
// all of needed data are available now, do the logic of authorization
return result;
}
}
Please note that the code in IsAuthorize body above is an example. While it will works, people might say it's not a good practice. But since IActivityAccessService is just a common simple service class, we can inject anything that wee need to it and modify the IsAuthorize method signature in any way that we want to. For example, we can just pass the filterContext.RouteData instead.
As for how to apply this to a controller or action:
[Authorize(Policy = "ActivityAccess")]
public ActionResult<IActionResult> GetResource(int resourceId)
{
return Resource;
}
hope this helps
I am a newbie in ASP.NET, and currently learning ASP.NET Identity. I know it's built on top of OWIN implementation by Microsoft, and I am also still learning that too. So, I came across the extension method CreatePerOwinContext in the Owin startup code, and I don't see a clear purpose of using it. Is it some kind of dependency injection container? What is the real purpose of the method? In what case it should be applied?
CreatePerOwinContext registers a static callback which your application will use to get back a new instance of a specified type.
This callback will be called once per request and will store the object/objects in OwinContext so that you will be able to use them throughout the application.
Let's say you have defined your own implementation of IdentityDbContext:
public class ApplicationDatabaseContext : IdentityDbContext<MyApplicationUser, MyRole, Guid, MyUserLogin, MyUserRole, MyUserClaim>
{
public ApplicationDatabaseContext() : base("<connection string>")
{
}
public static ApplicationDatabaseContext Create()
{
return new ApplicationDatabaseContext();
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Customize your table creation here.
#region USERS - INFOS
modelBuilder.Entity<UserInfo>()
.Property(p => p.FirstName)
.HasColumnType("varchar")
.HasMaxLength(70);
modelBuilder.Entity<UserInfo>()
.Property(p => p.LastName)
.HasColumnType("varchar")
.HasMaxLength(70);
modelBuilder.Entity<UserInfo>()
.Property(p => p.Address)
.HasColumnType("varchar")
.HasMaxLength(100);
modelBuilder.Entity<UserInfo>()
.Property(p => p.City)
.HasColumnType("varchar")
.HasMaxLength(100);
modelBuilder.Entity<UserInfo>()
.ToTable("UsersInfo");
#endregion
}
public DbSet<UserInfo> UsersInfo { get; set; }
}
and your implementation of UserManager:
public class ApplicationUserManager : UserManager<MyApplicationUser, Guid>
{
public ApplicationUserManager(IUserStore<MyApplicationUser, Guid> store) : base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new MyUserStore(context.Get<ApplicationDatabaseContext>()));
manager.UserValidator = new UserValidator<MyApplicationUser, Guid>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
manager.PasswordValidator = new PasswordValidator()
{
RequiredLength = 6,
RequireNonLetterOrDigit = false,
// RequireDigit = true,
RequireLowercase = false,
RequireUppercase = false,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<MyApplicationUser, Guid>(dataProtectionProvider.Create("PasswordReset"));
}
return (manager);
}
}
In your Owin Startup you will register the callback:
// IAppBuilder app
app.CreatePerOwinContext<ApplicationDatabaseContext>(ApplicationDatabaseContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
which will call the static method:
public static ApplicationDatabaseContext Create()
{
return new ApplicationDatabaseContext();
}
and
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
...
}
Now you will be able to access your database context and user manager in a simple straightforward way:
ApplicationDatabaseContext dbContext = context.OwinContext.Get<ApplicationDatabaseContext>();
ApplicationUserManager userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
In your ApiController (if you're using WebApi):
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
ApplicationUserManager applicationUserManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
What is the real purpose of the method? In what case it should be
applied?
To answer your question more directly, this is useless.
It's some sort of IoC factory, which some people like using.
This one makes you use theirs (IoC) over your choice.
(I don't like IoC, it feels like an anti-pattern for people who want to feel warm and fuzzy and use the term "architecture".)
But seriously, this pattern doesn't IoC interfaces, it IoC static factory functions! Who's idea was that? Why not just use the Factory function yourself? Now you have to remember (Google) an extra API call, and when you press F12 on Get, it takes you nowhere helpful.
What should you do instead then?
Personally, I'm a fan of using OO for this, remember OO? Pepperidge farm remembers. With OO, you remain in control, you can debug, log, and you can extend.
public class BaseApiController : ApiController
{
private AppDbContext _db = null;
protected AppDbContext db
{
get
{
if (_db == null)
{
_db = AppDbContext.Create(); //Hey look a proper factory that you can extend with other overloads! And I can debug this line - neat!
}
return _db;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_db != null)
_db.Dispose();
}
}
}
All this could be a waste of time, if someone finds some documentation why Microsoft engineers put this in, they might have a good reason why, but I doubt it, so let's upvote this answer in the meantime.
UPDATE 1
Here's the why, why it's there for Microsoft: https://blogs.msdn.microsoft.com/webdev/2014/02/12/per-request-lifetime-management-for-usermanager-class-in-asp-net-identity/
Basically, the UserManager and all them are built for this kind of structure. The Security checks occur in the pipeline, so why not have a singleton linked to the request, to reduce waste? Because it's hidden.
I would still recommend creating your own instance of the db context on a baseclass, it makes it much cleaner to use. If you really want, you can have a property in your baseclass which retrieves the singleton from the OwinContext.
How much time do we waste trying to work out these fancy APIs, and Authorise attributes and the like, when all we want to do is:
public void DoSomething()
{
DemandAuthenticated();
DemandAuthorised(typeof(somethingClass), "DoSomething");
}
Clearly, I prefer verbose code you can see.
Update 2
EF contexts should not be held as singletons, and certainly not through any IoC or repository pattern.
Generally, yes IoC can be good in situations. But specifically for a dbContext? No.
1) EF DB contexts are a unit of work, they should be short-lived. If you keep them running for a long time, the object cache will slow down queries, and updates/inserts to the underlying database get slower. It's designed to have short lifetime.
2) Also, EF contexts are already loosely coupled. You can change the RDBMS behind a context in the connection string, you can even use memory-only.
3) EF has LINQ which is very flexible, expressive, and type safe.
4) Database is not a business-level service for IoC it's a tool that services use to communicate with the database. Perhaps, You might have some kind of service IEmail that is accessed via IoC. But it should access the internal database using a new EF context that is disposed promptly after completion of queries.
5) Given 1-4 above, we certainly don't want any intermediate Interface layers (Service or Repository) to spoil all the benefits of using EF in the first place.
you may use typeof to get the name like this:
HttpContext.GetOwinContext().Get<ApplicationDbContext>(typeof(ApplicationDbContext).ToString());
Sorry if this is stupid question, because I'm a bit confused about .NET remoting and distributed object.
I want to write a webservice, and in one of its methods, I want user to pass one my object's instance as parameter. It will greatly reduces number of parameters, and help user call this method more effectively. I create some class, but when distributing them to client, only class name remains, all properties and methods are gone, just like this
public class CameraPackages
{
private readonly List<CameraPackage> _packages;
public CameraPackages()
{
_packages = new List<CameraPackage>();
}
public void AddNewCamera(CameraPackage package)
{
_packages.Add(package);
}
public void RemoveCamera(CameraPackage package)
{
if(_packages.Contains(package))
_packages.Remove(package);
else
throw new ArgumentException();
}
}
into this: (in Reference.cs)
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3082")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/")]
public partial class CameraPackages {
}
How can I do to allow user use my object?
Thank you so much.
Web Services will only serialise public properties, so you can't do that (in that way) using web services.
You will need to manage your list of objects client side, then send the data in a transfer object (a class with just properties).
Have a look at this.
I hope this makes sense. I have a ASP.NET web application that uses Entity Framework. I have added a couple of custom tables to the db and created a separate project to handle the CRUD operations for those tables. I chose the separate project because I don't want future upgrades to the application to overwrite my custom features.
My problem is this. How do I attach/combine my custom ObjectContext to the ObjectContext of the application? I want to use the same UnitOfWorkScope (already in the application) to maintain the one ObjectContext instance per HTTP request. Again, I don't want to add my ObjectSets to the application's ObjectContext for my reason listed above.
Here is some code:
Widget.cs
public partial class Widget
{
public Widget()
{
}
public int WidgetId {get;set;}
public string WidgetName {get;set;}
}
WidgetObjectContext.cs
public partial class WidgetObjectContext : ObjectContext
{
private readonly Dictionary<Type, object> _entitySets;
public ObjectSet<T> EntitySet<T>()
where T : BaseEntity
{
var t = typeof(T);
object match;
if(!_entitySets.TryGetValue(t, out match))
{
match = CreateObjectSet<T>();
_entitySets.Add(t, match);
}
return (ObjectSet<T>)match;
}
public ObjectSet<Widget> Widgets
{
get
{
if((_widgets == null))
{
_widgets = CreateObjectSet<Widget>();
}
return _widget;
}
}
private ObjectSet<Widget> _widgets;
In my WidgetManager class if I was using the application's ObjectContext I would query my tables like this:
var context = ObjectContextHelper.CurrentObjectContext;
var query = from c in context.ObjectSet .... etc
What I want would be to do something like this:
var context = ObjectContextHelper.CurrentObjectContext.Attach(WidgetObjectContext);
I know this won't work but that is the gist of what I am trying to accomplish. Hope this is clear enough. Thanks.
I don't think it is possible. ObjectContext creates entity connection which connects to metadata describing mapping and database. But you have to different sets of metadata - one for ASP.NET application and one for separate project. Simply you need two connection to work with these models => you need two ObjectContexts.
FYI: The previous answer was correct at the time of the answer. It is now possible to do this using the DbContext available in EF 4.1. The caveat is that you must use the code-first strategy in order to build your custom context. In other words, you won't be able to use EDMX files to accomplish this.
I'm trying to work out how to complete my implementation of the Repository pattern in an ASP.NET web application.
At the moment, I have a repository interface per domain class defining methods for e.g. loading and saving instances of that class.
Each repository interface is implemented by a class which does the NHibernate stuff. Castle Windsor sorts out the DI of the class into the interface according to web.config. An example of an implemented class is provided below:
public class StoredWillRepository : IStoredWillRepository
{
public StoredWill Load(int id)
{
StoredWill storedWill;
using (ISession session = NHibernateSessionFactory.OpenSession())
{
storedWill = session.Load<StoredWill>(id);
NHibernateUtil.Initialize(storedWill);
}
return storedWill;
}
public void Save(StoredWill storedWill)
{
using (ISession session = NHibernateSessionFactory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
session.SaveOrUpdate(storedWill);
transaction.Commit();
}
}
}
}
As pointed out in a previous thread, the repository class needs to accept an unit of work container (i.e. ISession) rather than instantiating it in every method.
I anticipate that the unit of work container will be created by each aspx page when needed (for example, in a property).
How do I then specify that this unit of work container instance is to be passed into the constructor of StoredWillRepository when Windsor is creating it for me?
Or is this pattern completely wrong?
Thanks again for your advice.
David
I have a persistence framework built on top of NHibernate that is used in a few Web apps. It hides the NH implementation behind an IRepository and IRepository<T> interface, with the concrete instances provided by Unity (thus I could in theory swap out NHibernate for, say, Entity Framework fairly easily).
Since Unity doesn't (or at least the version I'm using doesn't) support the passing in of constructor parameters other than those that are dependency injections themselves, passing in an extant NH ISession isn't possible; but I do want all objects in the UOW to share the same ISession.
I solve this by having a controlling repository class that manages access to the ISession on a per-thread basis:
public static ISession Session
{
get
{
lock (_lockObject)
{
// if a cached session exists, we'll use it
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
{
return (ISession)PersistenceFrameworkContext.Current.Items[NHibernateRepository.SESSION_KEY];
}
else
{
// must create a new session - note we're not caching the new session here... that's the job of
// BeginUnitOfWork().
return _factory.OpenSession(new NHibernateInterceptor());
}
}
}
}
In this example, PersistenceFrameworkContext.Current.Items accesses an IList<object> that is stored either ThreadStatic if not in a Web context, or within HttpContext.Current.Items if it is in a Web context (to avoid thread-pool problems). The first call to the property instantiates the ISession from the stored factory instance, subsequent calls just retrieve it from storage. The locking will slow things down slightly but not as much as just locking an appdomain-scoped static ISession instance.
I then have BeginUnitOfWork and EndUnitOfWork methods to take care of the UOW - I have specifically disallowed nested UOWs because frankly they were a pain to manage.
public void BeginUnitOfWork()
{
lock (_lockObject)
{
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
EndUnitOfWork();
ISession session = Session;
PersistenceFrameworkContext.Current.Items.Add(SESSION_KEY, session);
}
}
public void EndUnitOfWork()
{
lock (_lockObject)
{
if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
{
ISession session = (ISession)PersistenceFrameworkContext.Current.Items[SESSION_KEY];
PersistenceFrameworkContext.Current.Items.Remove(SESSION_KEY);
session.Flush();
session.Dispose();
}
}
}
Finally, a pair of methods provide access to the domain-type-specific repositories:
public IRepository<T> For<T>()
where T : PersistentObject<T>
{
return Container.Resolve<IRepository<T>>();
}
public TRepository For<T, TRepository>()
where T : PersistentObject<T>
where TRepository : IRepository<T>
{
return Container.Resolve<TRepository>();
}
(Here, PersistentObject<T> is a base class providing ID and Equals support.)
Access to a given repository is thus in the pattern
NHibernateRepository.For<MyDomainType>().Save();
This is then facaded over such that you can use
MyDomainType.Repository.Save();
Where a given type has a specialised repository (ie needs more than it can get from IRepository<T>) then I create an interface deriving from IRepository<T>, an extending implementation inheriting from my IRepository<T> implementation, and in the domain type itself I override the static Repository property using new
new public static IUserRepository Repository
{
get
{
return MyApplication.Repository.For<User, IUserRepository>();
}
}
(MyApplication [which is called something less noddy in the real product] is a facade class which takes care of supplying the Repository instance via Unity so you have no dependency on the specific NHibernate repository implementation within your domain classes.)
This gives me full pluggability via Unity for the repository implementation, easy access to the repository in code without jumping through hoops, and transparent, per-thread ISession management.
There's lots more code than just what's above (and I've simplified the example code a great deal), but you get the general idea.
MyApplication.Repository.BeginUnitOfWork();
User user = User.Repository.FindByEmail("wibble#wobble.com");
user.FirstName = "Joe"; // change something
user.LastName = "Bloggs";
// you *can* call User.Repository.Save(user), but you don't need to, because...
MyApplication.Repository.EndUnitOfWork();
// ...causes session flush which saves the changes automatically
In my Web app, I have session-per-request, so BeginUnitOfWork and EndUnitOfWork get called in BeginRequest and EndRequest respectively.
I have a pretty similar structure to yours, and here's how I solve your question:
1) To specify my container on each method, I have a separate class ("SessionManager") which I then invoke via a static property. By doing so, here's an example using my Save implementation:
private static ISession NHibernateSession
{
get { return SessionManager.Instance.GetSession(); }
}
public T Save(T entity)
{
using (var transaction = NHibernateSession.BeginTransaction())
{
ValidateEntityValues(entity);
NHibernateSession.Save(entity);
transaction.Commit();
}
return entity;
}
2) My container is not created on each ASPX page. I instantiate all of my NHibernate goodness on the global.asax page.
** A few more things spring up **
3) You don't need to have a helper to instantiate the Load. You might as well use Get instead of Load. More information # Difference between Load and Get.
4) Using your current code, you would have to repeat pretty much the same code for each domain object you need (StoredWillRepository, PersonRepository, CategoryRepository, etc..?), which seems like a drag. You could very well use a generic class to operate over NHibernate, like:
public class Dao<T> : IDao<T>
{
public T SaveOrUpdate(T entity)
{
using (var transaction = NHibernateSession.BeginTransaction())
{
NHibernateSession.SaveOrUpdate(entity);
transaction.Commit();
}
return entity;
}
}
In my implementation, I could then use something like:
Service<StoredWill>.Instance.SaveOrUpdate(will);
Technically, the answer to my question is to use the overload of container.Resolve which allows you to specify the constructor argument as an anonymous type:
IUnitOfWork unitOfWork = [Code to get unit of work];
_storedWillRepository = container.Resolve<IStoredWillRepository>(new { unitOfWork = unitOfWork });
But let's face it, the answers provided by everyone else have been much more informative.