ASP.NET Storing Cross Request Data - c#

In my application I have this entity:
public class Franchise
{
public Guid Id {get;set;}
public string Name {get;set;}
}
When each of my users log in, they are associated with a franchise.
There is another entity:
public class Client
{
public Guid FranchiseId {get;set;}
public virtual Franchise Franchise {get;set;}
public string Name {get;set;}
/* other useful client information */
}
Depending on my user franchise association will determine which clients they shall see (or are allowed to see)
So equivalent of doing
dbContext.Set<Client>().Where(x => x.FranchiseId.Equals(associatedFranchiseId));
I was wondering what the options where of storing that associatedFranchiseId so each request for data can use that Id to select the appropriate dataset.
APPROACH 1
I created a service that gets these associations and returns the correct dataset. I thought I could use this in each controller where I need to get the information. But I thought this maybe costly in database lookup terms. It would have to based on the User, so getting that out of the request.
I just am not sure how I would go about doing this.
The process is:
User Logs In
Application determines the associated franchise
User request some information
The request uses the associated franchise to select the right dataset

I've used something similar and use the session and application spaces for the objects.
So, when the application fires up load all the franchise objects into application:
Application["Franchise"] = MethodToLoadFranchiseInfo();
You can then access this at anytime via Franchise f = Application["Franchise"];
Similarly, for the clients, when they login, load the client info into Session in a similar fashion.
The only caveat if that you'll need to refresh the Application object when there's an update, and same for the session, or require a log out and log back in.
This way you only have one hit to the database and in memory accessible objects!
* Edit to Add *
Just had some more thoughts on this, and probably something I'll look to implement myself. If you put a timestamp in both the application and session objects, if the session object is older than the application object (which will be updated centrally being application wide), then hit the database and refresh the session object.
That way you do not get the log out / log back in situation when something is changed by the backend / admin.

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

Maintain the model lifetime in MVC application

I am new to MVC and I have very simple problem.
When user login to my application I need to create a specific object (model) for the user for eg UserObject.
This object is unique to current logged in user and should only be disposed when user click on logout.
I don’t know how to maintain the lifetime of the object. As if I create object in Action method of controller class then as soon as the request is finished I lose the reference of the object.
How this should have been done?
The lifetime of your models are only going to be as long as the request. So each time the user goes to another page or refreshes, the MVC framework is going to instantiate a new controller (and model within). Otherwise your server would have a ton of static objects floating around in memory which would use up a lot of resources and wouldn't scale.
In order to manage state, you are going to need to use other methods such as sessions/cookies and a database.
So let's say the user logs in via /User/Login. This routes the request to an action named UserController.Login().
Inside this action, it instantiates a UserModel.
public ActionResult Login(string username, string password) {
var userModel = new UserModel();
if (userModel.Authenticate(username, password)) {
// Setup your session to maintain state
Session["username"] = username;
} else {
return View("Login");
}
return View("LoginComplete");
}
You might want the user model to actually create the session, but I've shown it here for clarity.
The user model authenticates the user, and then you create a session just like you would in a traditional non-MVC site.
Then in subsequent requests, you will want to authorize the user, and use any session data you have to retrieve state information.
public ActionResult SuperSecretPlace() {
var userModel = new UserModel();
string username = Session["username"]
var user = userModel.GetUserByUsername(username);
if (user == null) throw new HttpException(401, "User is not authorized.");
return View("SuperSecretPlace", user);
}
In the action above, the UserModel might do something like query a database to retrieve the user's data so you can pass it in to the corresponding view.
If you want to make life easier, you might want to just use .NET's built in forms authentication:
http://www.codeproject.com/Articles/578374/AplusBeginner-splusTutorialplusonplusCustomplusF
For more info about the lifecycle of MVC:
http://www.dotnet-tricks.com/Tutorial/mvc/TbR0041112-Asp.net-MVC-Request-Life-Cycle.html
http://www.asp.net/mvc/overview/getting-started/lifecycle-of-an-aspnet-mvc-5-application
Actually what you are trying to achieve is passing model from controller to controller which is not possible. When an action is executed the context of the model object is disposed at the view and it can cannot be passed from controller to controller. You have to create a new object repopulate it and use it to achieve the goal in different controller.If you need the data to be persisted you can use sessions but still you need to create an object of the model in every controller.
The following image is for your reference as to see what to use when passing data between model-view-controller. Please feel free to ask if you need more information on this.
As opposed to the other aswers I would not use session as it has quite some disadvantages (scalability, pessimistic concurrency which blocks concurrent calls, app pool recycling...). Why you should not use session is documented in a lot of places like here or here.
Instead, I would store it in a cookie.
However, be sure to not store confidential or sensitive data. Whatever you use (cookies or session), it can be tampered with or stolen. If you are dealing with sensitive information, you need other solutions. Read also more about secure cookie solution here.

access Auth() object from TryAuthenticate

I am logging into my service from a c# client like so:
serviceClient.Send<ServiceStack.ServiceInterface.Auth.AuthResponse>(
new ServiceStack.ServiceInterface.Auth.Auth() {
UserName = "xxx",
Password = "yyy" }
);
I would now like to use one of the unused strings in the Auth class to pass some additional information (like a programid). I am using my own subclassed CredentialsAuthProvider. Two questions:
Do you recommend any of the "extra" properties in the Auth class to stuff my programid over any others? I was considering using "State", will that mess anything up if I put a string in there?
Is there a way from within the TryAuthenticate override of my CredentialsAuthProvider to access the Auth class instance that was sent to me (so I can access the programid that I stuck into the State property).
Thank you.
Answered half of my question.
Not sure if any of the properties are better than any other, but I'm using "State" to stuff some extra data. Now that multiple end user programs are accessing the same service, sending a program ID in the State property lets me log the programs attempting to log into the service, along with the users.
If you are authenticating by overriding CredentialsAuthProvider, you can override the Authenticate method to gain access to the Authenticate object that is passed in from the user. From there, you can read the State property (or any other).

Categories

Resources