Access session in class library. - c#

I am developing an application architecture that uses 2 sub projects:
a) asp.net web application (it covers user interface and business logic) and
b) class library. (it covers data access layer)
After system user successfully logs in , the user information is stored in a session object.
The problem I am facing is when I try to access that session object in class library project(data access layer), it always returns null.
I need to access the session object in class library project because, in my case each user has their own username and password for database access(for security reasons);
So, How how do i read and write from/to session object in class library project

Use the System.Web.HttpContext.Current.Session object.

First of all, as Peri correctly noticed - you need to think again if having separate database logins for each user is a good idea - because you loose connection pooling (different users won't be able to reuse existing connections - and creating a new sql connection is quite expensive).
If you really wish to keep separate database users, I would create interface to abstract session from data access:
public interface ILoginDataService
{
LoginData Current { get; }
}
And implementation would pass login data from session. In such way you won't have session dependency to session in your data access logic - so it will be more testable, also you'll separate concerns.

Here is the code I used within a library to get session information.
public static string Entity()
{
string entity = "";
HttpContext httpContext = HttpContext.Current;
if (httpContext.ApplicationInstance.Session.Count > 0)
entity = httpContext.ApplicationInstance.Session["EntityCode"].ToString();
return entity;
}

I am having an ASP.Net application which uses session. I am able to access it in my app_code files using [WebMethod(EnableSession = true)] for the function. I am not sure whether this is your problem. I also faced session value as null when I removed (EnableSession = true) on the method.

using System.Web;
namespace ClassNameSpace
{
public class Class1 : IRequiresSessionState
{
private string sessionValue => HttpContext.Current.Session["sessionKey"].ToString();
}
}

Related

Alternative to Session Variable

I am trying to find an alternative to using a session variable. In my solution I have a project that is referenced by an ASP.NET web application and a console application. Both these applications can make changes to data and when a change is made the ID of the user making the change is logged against that row.
So if it was just the ASP.NET app making changes, it could do something like myObj.LastUpdatedByID = Session["userid"]. Given that the command line app needs to make changes and doesn't have a session, what alternative could I use that has the equivalent of session scope in ASP.NET but is also available in the console app scope?
I've had a look at MemoryCache, but that seems to be application level in ASP.NET.
I don't want to go down the line of passing the user ID through to each call.
Would doing something like checking for a HttpContext and if there is, pull from the session and if there isn't, pull from MemoryCahce? Or is there a better way of doing it?
EDIT:
The user ID is specifically set in the console app depending on what action is being carried. The console app is used for automated processes and there are numerous actions it undertakes. So for example, the sending email process would be carried out by user ID 1 and the delete old files process would be carried out by user ID 2. In some instances, the user ID would be set to the user ID that last made the change to that row of data.
EDIT:
Some example code (stripped for brevity). You can see I am using the MemoryCache here, which as I understand would be application wide and therefore not usable in ASP.NET app:
public class Base(
{
private int auditID = -1;
public int AuditID
{
get
{
if (this.auditID <= 0)
{
ObjectCache memCache = MemoryCache.Default;
this.auditID = ((int)memCache["CurrentUserID"]);
}
return this.auditID;
}
}
}
public class MyObject : Base
{
public int LastUpdatedByID { get; set; } = 0;
public bool Save()
{
bool b = false;
this.LastUpdatedByID = this.AuditID;
//Call to DB here...
return b;
}
}
If the data needs to be persistent across application then you can't use Session or HttpContext.Cache since those are dependent on current HttpContext which you don't have in console app.
Another way, would be to store the data in some persistent data store like Database or distributed cache like Redis Cache / Azure Mem Cache

How can I dynamically set connection string in MVC 5 based on incoming request?

I have an MVC 5 application that is currently single tenant only, but that is becoming unmanageable as our client-base grows.
I would like to turn this application into a multi-tenant app, accessing a distinct database for each client.
The client's are easily distinguishable by their domain, which I can access through Request.Url.Host or other methods, but once I have this property, I am having trouble setting it in the Business logic project within the context of that request only.
The Business logic project is referenced by the main Web project, but that project is blink to the Request object, so I do not know how to get that session information dynamically each time the baseDataAccess (which contains the connection strings) object is instantiated.
I've spent many many hours on this, and have tried using Ninject to resolve the dependency with no success. I just can't seem to figure out how to get the dynamic Request object or any of its properties to assign transiently to the baseDataAccess object.
The last thing I tried was using and IActionFilter using the OnActionExecuting method, but I am still unable to figure out how to set the value of the URL for each request dynamically in a project that has no context for the current request.
This is the class I want to set dynamically. the _connectionString is the dynamic property. I have methods to build the connection string based on the url, so if I can set the _domain property dynamically and transiently I'll be able to get the connection string.
public class baseDataAccess : IDataAccess
{
private static IClientConnection _clientConnection;
private static string _connectionString;
public static string _domain;
...
This is the last attempt I made, adding the OnActionExecuting method to each controller. How can I set these properties dynamically and transiently?
public void OnActionExecuting(ActionExecutedContext filterContext)
{
IClientConnection client = new ClientConnectionFactory(Request.Url.Host);
IDataAccess dataAccess = new baseDataAccess(client);
}
I'm have the same need for my application. I have to set the connection String with the user information depending on the user login. I added a reference on System.Web to get the Session object in my business layer.
The main idea is, to store the current user in the Session and let the business logic access this Session with HttpContext.Current.Session now my database classes can read the connection string dynamically on every single access to the database.
And as the user session is available in any library that has the System.Web reference, it can be used application wide. So there is no problem setting the connection string on the Session_Start event depending on the request from the user.

Web Api User Tracking

I am in need of help with Web Api.
I am setting up a multi tenant system when each tenant has there own database of data using code first EF and web api (so that I can create multiple app platforms)
I have extended the standard ASP.NET Identity to include a client id and client model which will store all tenants and their users.
I have then created another context which tracks all the data each tenant stores.
Each tenant holds a database name which I need to access based on the authenticated user.
Not getting the user id from each api controller seems easy:
RequestContext.Principal..... etc then I can get the client and subsequently the client database name to pass to the database context however I am trying to implement a standard data repository pattern and really hate repeating myself in code yet the only way I see it working at the moment is to:
Application calls restful api after authorisation
Web Api captures call
Each endpoint gets the user id and passes it to the data store via the interface and subsequently into the data layer retrieving the database name for the context.
What I have a problem with here is each endpoint getting the user id. Is there a way to "store/track" the user id per session? Can this be achieved through scope dependency or something similar?
I hope that makes sense but if not please ask and I will try to clarify further, any help will be greatly appreciated.
Thanks
Carl
ASP WebApi does not have a session context. You may use a cookie or a request token identifier (pass this token back from login and use this token as a parameter for further API calls).
This is something I've developed some time ago. I'm simply creating a new class deriving from ApiController and I'm using this class as a base for all other API class. It is using the ASP.NET cache object which can be accessed via HttpContext. I'm using the current user-id as a reference. If you need something else, you may use another way of caching your data:
public abstract class BaseController: ApiController
{
private readonly object _lock = new object();
/// <summary>
/// The customer this controller is referencing to.
/// </summary>
protected Guid CustomerId
{
get
{
if (!_customerId.HasValue)
{
InitApi();
lock (_lock)
{
if (User.Identity.IsAuthenticated)
{
Guid? customerId = HttpContext.Current.Cache["APIID" + User.Identity.Name] as Guid?;
if (customerId.HasValue)
{
CustomerId = customerId.Value;
}
else
{
UserProfile user = UserManager.FindByName(User.Identity.Name);
if (user != null)
{
CustomerId = user.CustomerId;
HttpContext.Current.Cache["APIID" + User.Identity.Name] = user.CustomerId;
}
}
}
else
{
_customerId = Guid.Empty;
}
}
}
return _customerId.GetValueOrDefault();
}
private set { _customerId = value; }
}
// ... more code
}
Do not blame me on the "lock" stuff. This code was some kind of "get it up and running and forget about it"...
A full example can be found here.
Maybe I am far from truth but Web API is state less so you dont really have a session to track

Ninject session scope concept in MVC3

I am building a MVC3 app using Ninject framework. I have a service that is time-consuming to initialize, and at the end this service will has an object that contains user-specific information, then I need to re-use that service as long as the user session is active, so that I can avoid to initialize that service again and again
So my question is
When I bind the service using Ninject what kind of scope should I pick, there is no session per scope in Ninject, so what is the best way to implement the requirement? or did I went to a wrong direction at all?
I've created a custom provider for one of my services that will create the service based on username details that is grabbed from current Controller.User.Identity.Name. The code below won't work because the userName local variable is missing, how can I pass the user name value into my custom provider via Ninject, so that I can pick it up from IContext??
public class TfsConnectionManagerProvider : Provider<TfsConnectionManager>
{
protected override TfsConnectionManager CreateInstance(IContext context)
{
Uri serverUri = new Uri(ConfigurationHelper.TfsServerUrl);
// Connect to the server without impersonation
using (TfsTeamProjectCollection baseUserConnection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(serverUri))
{
// Get the identity management service
IIdentityManagementService ims = baseUserConnection.GetService<IIdentityManagementService>();
// Get the identity to impersonate
TeamFoundationIdentity identity = ims.ReadIdentity
(
IdentitySearchFactor.AccountName,
userName, //NOTE: How can I get user name value from IContext???
MembershipQuery.None,
ReadIdentityOptions.None
);
// Connect using the impersonated identity
using (TfsTeamProjectCollection impersonatedConnection = new TfsTeamProjectCollection(serverUri, identity.Descriptor))
{
WorkItemStore store = impersonatedConnection.GetService<WorkItemStore>();
return new TfsConnectionManager
{
Store = store
};
}
}
}
}
A session scope is intentionally not offered in Ninject, because having services in a session state is wrong in almost every situation. You should be very carefully about using session state because it brings a lot of disadvantages.
Try to have a stateless application in first place.
If there is a good reason for having data in session scope then put that data (not the services) into the session state and use services that are in singleton, transient or request scope for the processing (separation of data and functionality).
I turn out to use custom Provider for creating the instance and in the custom provider I checked if it exists in session or not.
The binding is done as following
Bind<IRepository>().ToProvider(new TfsRepositoryProvider());
The custom Provider is below
public class TfsRepositoryProvider : Provider<TfsRepository>
{
private const string SesTfsRepository = "SES_TFS_REPOSITORY";
protected override TfsRepository CreateInstance(IContext context)
{
// Retrieve services from kernel
HttpContextBase httpContext = context.Kernel.Get<HttpContextBase>();
if (httpContext == null || httpContext.Session == null)
{
throw new Exception("No bind service found in Kernel for HttpContextBase");
}
return (httpContext.Session[SesTfsRepository] ?? (
httpContext.Session[SesTfsRepository] = new TfsRepository(context.Kernel.Get<IWorkItemStoreWrapper>()))
) as TfsRepository;
}
}
Okay, you can cache / store the user information in your application and only call the external service if you don't have (recent) user information. In your user information retrieval "layer", you just program those two possibilities.
Where you cache, it entirely up to you. You can store this information for example in a local database.
Apparently I understood you wrong, my apologies (below my original answer).
You can use for example an (abstract) factory that holds a static
member of your service (for example) so it will be reused.
Although depending on your service, this might have some unwanted side
effects (I did this once with Data Services and in an ASP.NET MVC3
application my data context was kinda screwed due to some magic that
happened). All I want to say with this is: be careful and test it
well.

Passing environment variables to Data Access Layer

Every stored procedure we write has to have clientip, serverip, windows username, etc passed on to it.
The question is how do I efficiently pass these to DAL?
I'm assuming this is a web app in ASP.NET. If that's the case, you have access to all these things in the context of a web request outside of the web application through the following static instance:
System.Web.HttpContext.Current
If everything you need is standard stuff that you usually have in the Request, Response, and User objects that are available by default at the Page level, then this should be all you need. If you need information that is custom to your web app, then Ben's answer (above) should work.
You should have all of the above data accessible either in the System.Environment class, or in your own Thread Principal of some kind. Your DAL can easily pull in from both or either of those sources.
Create a class to hold this data, a factory to build it and helper methods to consume it.
IUserContext
{
int param1 {get;set;}
int param2 {get;set;}
SqlParameter[] GetSqlParameters();
}
UserContext : IUserContext{}
UserContextFactory
{
internal IUserContext IUserContextFromRequest(){}
}
Good luck

Categories

Resources