I need to store the current user name for every save request/user in SQL table. It is MVC 4 based application and hosted in IIS server. Also, it is an internal tool and NTLM based authentication.
I have got the username of current user using HttpContext.Current.User.Identity.Name My question is how the global variable reacts in MVC? What would happen for "currentUser" variable when multiple requests comes? Will the currentUser creates new value for every requests? Please help me to understand.
Sample Code:
public class ClearCacheController : ApiController
{
private string currentUser = HttpContext.Current.User.Identity.Name.ToLower();
public void method1()
{
SaveValue1(currentUser);
}
public void method2()
{
SaveValue2(currentUser);
}
public void method3()
{
SaveValue3(currentUser);
}
}
Controllers are instantiated and disposed for each unique request. So, something like User.Identity.Name is not really a global variable. It's an instance variable on the controller. (Well, User is an instance variable on the controller, while Identity is an instance variable on User, etc.). Long and short, it will only hold the value of the user who made the particular request being executed, not any user making any request.
Related
I have one main mvc application that will call 3 web api applications and will write logs using log.LogInformation() for each method hit and each controller in the mvc project. I created a variable named username and have each of the logs to include that username at the end of the message. I.e. log.LogInformation("You have hit the home page of the mvc project... {#Username}, username)so at the end of every log message I am using {#Username} and passing username. I am wanting to group all the entire logs based on that variable username. Is there a way to group all the entire logs that get recorded to logger, starting from the mvc project to every web api project called? I am using Serilog to write the logs.
Follow up:
So after reading Log scopes and using BeginScope I could create another method in my mvc project in my last controller as so:
public IActionResult GetAllLogs()
{
using (_logger.BeginScope("Gathering all the logs created for {#Username}", HomeController.username))
{
}
}
So leaving it as will be able to gather all the logs from the mvc project that includes the web api projects logs? I wouldn't need to do anything inside of the using() statement?
You can check for Log scopes (Read here). With BeginScope, all the log statement inside the scope will have the property logged as custom property.
For ex:, the Scope is started at SomeAPI API which invokes Method1 -> Method2 -> Method3DoesTheLogging. Now till method Method3DoesTheLogging, no property need to be passed to be logged in log statement. The logging framework will automatically attached the custom property which were defined in BeginScope.
public IActionResult SomeAPI()
{
using (_logger.BeginScope("Gathering all the logs created for {#Username}", HomeController.username))
{
Method1();
}
}
public void Method1()
{
Method2();
}
public void Method2()
{
Method3DoesTheLogging();
}
public void Method3DoesTheLogging()
{
_logger.LogInformation("This log statement will log the username automatically as custom property".);
}
So with Log scope, you don't need to pass the property to nth function level. Since, property is logged as a custom property so you can do grouping, filtering e.t.c,
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
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
I started with a WebForms .NET 4.51 application. I then added WebAPI to the same application. In Session_Start() I create a variable instance that I store within the session as follows:
public class Global : HttpApplication
{
protected void Session_Start(object aSender, EventArgs aEventArgs)
{
//Create an object to hold all the settings for the user in the session. This is only loaded once we
//have a user successfully logged in
HttpContext.Current.Session[SYSTEM_SETTINGS_SESSION_KEY] = new SystemSettings();
}
}
and I have a simple property accessor as follows:
public class Global : HttpApplication
{
public static SystemSettings SystemSettings
{
get
{
if (HttpContext.Current == null)
return null;
return HttpContext.Current.Session[SYSTEM_SETTINGS_SESSION_KEY] as SystemSettings;
}
}
}
The above all works well when I am accessing the property from code except when I attempt to do this from within a WebAPI controller as follows via the property from above viz Global.SystemSettings:
public class EmailActivitiesController : ApiController
{
emailBody = EmailToClientsTemplateBuilderHelper.TemplateContentBuild(emailBody, Global.SystemSettings);
}
When I inspect HttpContext.Current.Session it is NULL.
So why is the Session collection null when accessed from the WebAPI controller?
I need to store use the information related to the user's session in the WebAPI controller, so do I need to store things differently now?
UPDATE
The accepted solution also worked for WebAPI 1 which is what the application is using.
This is because WebApi does not have Session enabled by default. WebApi is trying to encourage you to move towards stateless HTTP and RESTful APIs.
I strongly urge you to rework your design without sessions.
With this said, you can enable Session in WebApi 2 by adding this to Global.asax
protected void Application_PostAuthorizeRequest()
{
System.Web.HttpContext.Current.SetSessionStateBehavior(
System.Web.SessionState.SessionStateBehavior.Required);
}
I'm using VS2010,C# to develop an automation site (ASP.NET web app) which may have up to hundreds of users at once. I'm almost finished creating the site, but I KNOW I HAVE MADE some mistakes and one of them is using public static variables at codebehind pages instead of using sessions for each user, now when user A changes a setting in a page, USER B also views the page exactly the same way that user A views it!, rather than viewing the page in default state. I have a question:
where should I declare my sessions for each user? when users login, I create a session for each one, and this is the only session that I've used so far:
Session.Add("userid" + myReader["ID"].ToString(), "true");
should I create other necessary sessions right here? i.e. at login time? for instance I have declared some public static variables at a page responsible for viewing DB:
public static string provinceid = "0";//0 means all
public static string branchid = "0";
public static string levelid = "0";
public static string groupid = "0";
public static string phrase = "";
should I declare one session for each of them at login time? or can I declare them at startup of each page?
thanks
The Session object is unique per user already - you do not need to "create" it.
Using static variables would cause these items to be shared across all threads (so all users). These should probably be converted to session variables.
Instead of your statics, you would just do something like this:
Session["provinceid"] = "0";
Session["branchid"] = "0";
Session["levelid"] = "0";
Session["groupid"] = "0";
Session["phrase"] = "";
As Oded mentioned in his answer, the Session is already unique to the user, so no need for using the "Add" method.
Whenever you are done with this information (user logs out, etc), you can use the Session.Clear() method, which removes all the keys and values from the Session object.
I KNOW I HAVE MADE some mistakes and one of them is using public
static variables at codebehind pages
You are right about that. That's a pretty bad thing to do on a web app.
You don't need to create a user Session since it's already created automatically when the user hits your website the first time. What you need in order to use Session the way you intend to is something like this:
//Store value
Session["Key"]=myValue;
//retrieve field
var myValue = Session["Key"];
You can do this on any page you want since Session is a global object; it doesn't need to be done on the login page, but whenever you need to store anything that's specific to the user.