I have production IIS server with some ASP.NET MVC app. I got some tricky bug which I can't capture. It's linked to session data. How can I export/see/view such user session? There is default IIS configuration for session storing -- in-process.
EDIT
By the way I have necessary appropriate user session ID.
EDIT2
Ok, guys, so even if I can't export that data right now, could you please point me at some session state server or something similar, which I can use for storing session data and view it further?
I kniw SQL Server can, but it is very heavy for such issue.
Chris is right following on his Idea, you could write a routine that would output the content of your session objects to a file (a kind of a custom log).
//Controller Action where you store some objects in session
public ActionResult Index()
{
var myObj = new { strTest = "test string", dtTestValue = DateTime.Now, listTest = new List<string>() { "list item 1", "list item 2", "list item 3" }};
Session["test1"] = "Test";
Session["test2"] = myObj;
return View();
}
//Controller Action where you output session objects to a file
[HttpPost]
public ActionResult Index(FormCollection form)
{
//Routine to write each sessionObject serialized as json to a file
foreach (string key in Session.Keys)
{
var obj = Session[key];
JavaScriptSerializer serializer = new JavaScriptSerializer();
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\Users\Public\CustomAspNetLog.txt", true))
{
file.WriteLine(DateTime.Now.ToString() + "\t" + serializer.Serialize(obj));
}
}
return View();
}
If you need to call that routine often, you can put it in some helper class and call it whenever you want in your controller actions. Then you are able to inspect true data inside Session at every step you find necessary.
No, you will need to write a routine to export the session data as and when required.
KSeen
There is a better option to store sessions than a StateServer i.e Distributed Cache provider.
Alachisoft provides NCache Express which is totally free.You can use it to store your sessions.Here is how you do it.
Install NCache on each web server.
Define a distributed cache: Make sure you test the distributed cache to ensure it is properly working.
Modify web.config file: to add the SessionState Provider information and the name of the cache you've just created.
<sessionState cookieless="false" regenerateExpiredSessionId="true"
mode="Custom"
customProvider="NCacheSessionProvider" timeout="1">
<providers>
<add name="NCacheSessionProvider"
type="Alachisoft.NCache.Web.SessionState.
NSessionStoreProvider"
cacheName="myreplicatedcache"
writeExceptionsToEventLog="false"
AsyncSession="false"/>
</providers>
</sessionState>
Please note that Version=3.2.1.0 should match the specific NCache Express version you've downloaded. Once you do this, you're ASP.NET application is ready to start using distributed sessions.
Related
In an MVC5 application I am using Windows Authentication and wanted to use our Active Directory Groups as roles as this is strictly and intranet application. I am using the WindowsTokenRoleProvider as so:
<roleManager defaultProvider="WindowsProvider" enabled="true" cacheRolesInCookie="false">
<providers>
<add name="WindowsProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
I have tried a few other variations of that config including using the cookie cache, but the end result is that it takes ~20 seconds per group check. I check role like this:
User.IsInRole(#"Domain\UserName")
Is there something I have completely missed in setting this up? I can't believe it would be normal for authentication to take 20 seconds per check. The user I am checking is in ~50 groups, but I didn't think that would be enough to slow it down so much.
So best solution at this point seems to be this stackoverflow question
I will probably play around with how the roles get checked/added to see if I can pinpoint the issue, but I wouldn't expect this slowness from only being in 50 groups.
UPDATE:
So while actually enumerating my groups I found my user was in over 400 groups which might explain why it took so long. I still don't under stand why the IsInRole method on user would call GetRolesForUser instead of just calling IsUserInRole directly, but this makes things exponentially faster
UPDATE 2:
Old answer was deleted so here is my class:
public class CustomWindowsTokenRoleProvider : WindowsTokenRoleProvider
{
public override string[] GetRolesForUser(string username)
{
List roles = null;
string key = String.Concat(username, ":", base.ApplicationName);
Cache cache = HttpContext.Current.Cache;
if (cache[key] != null)
{
roles = new List(cache[key] as string[]);
}
if (roles == null)
{
roles = new List();
// AppSettings.APPLICATION_GROUPS is an IEnumerable that returns just the groups that my application is interested in checking against
foreach (string role in AppSettings.APPLICATION_GROUPS)
{
if (base.IsUserInRole(username, role));
{
roles.Add(role);
}
}
cache.Insert(key, roles.ToArray(), null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
}
return roles.ToArray();
}
}
I'm following this article in which is described how to assign roles to users when theiy log-in using forms authentication:
public void Application_AuthenticateRequest( Object src , EventArgs e )
{
if (!(HttpContext.Current.User == null))
{
if (HttpContext.Current.User.Identity.AuthenticationType == "Forms" )
{
System.Web.Security.FormsIdentity id;
id = (System.Web.Security.FormsIdentity)HttpContext.Current.User.Identity;
String[] myRoles = new String[2];
myRoles[0] = "Manager";
myRoles[1] = "Admin";
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id,myRoles);
}
}
}
I put the role logic in the event handler, so I basically don't need a role provider. Nonetheless, in order to run this, appears that I must enable Role Provider in web.config. Sadly, if I just put:
<roleManager enabled="true"/>
it results in runtime errors related to a failed connection to the SQL server, like if I chose AspNetSqlRoleProvider as Role Provider.
What should I do to have roles working this way? How can I choose to use no role provider, or how should I implement a dummy one (if it makes any sense)?
You shouldn't need to enable roleManager in web.config - after all, people used to use roles with .NET 1.x before roleManager came along.
One thing that roleManager will do for you that you haven't done in your code is set Thread.CurrentPrincipal to HttpContext.Current.User. If you're relying on this (e.g. using PrincipalPermissionAttribute), then you need to add this:
Thread.CurrentPrincipal = HttpContext.Current.User;
Otherwise, I'd expect it to work: what symptoms are you seeing that makes you think it isn't working?
As for implementing a dummy RoleProvider, it's easy enough: for example see this MSDN article.
You only need to implement the GetRolesForUser and IsInRole methods; the other methods can simply throw NotSupportedException.
I have a web forms application. When the user logs in I would like to retreive settings from the database that relates to that user.
So that I don't need to make a database call in the application when the settings are needed, I'm thinking about using the session object to store the values. Is this a good solution?
And if: Should I use for example a hastable or just store each value in the session.
Session["SomeSetting"] = true;
Session["smtp"] = "Somesmtp.ee.no";
or
Hastable settings New Hastable();
settings.Add("SomeSetting",true);
settings.Add("smtp","Some...");
There will be something like maximum 30 settings..
I would create a class that holds the data and put that class in a Session object.
Something like this:
public class MyInfo{
private String name {get;set};
private String smtp {get;set};
public MyInfo(){}
public void fill(){}//fill from DB
}
Once the users come to your page you set up a new MyInfo object for that user and put it into a Session like this:
MyInfo myinfo = new MyInfo();
myinfo.fill();
Session["user_info"] = myinfo;
If you want to save user-specific settings or state then you can use Session but these settings for an application level then I suggest you to use <appSettings> in web.config.
I'm still relatively new to .NET and ASP.NET MVC, and I have had a few occasions where it would be nice to store information retrieved from the DB temporarily so it can be used on a subsequent server request from the client. I have begun using the .NET Session to store this information, keyed off of a timestamp, and then retrieve the information using the timestamp when I hit the server again.
So a basic use case:
User clicks 'Query' button to gather information from the system.
In JS, generate a timestamp of the current time, and pass this to the server with request
On server, gather information from DB
On server, use unique timestamp from client as a key into the Session to store the response object.
Return response object to client
User clicks 'Generate Report' button (will format query results into Excel doc)
Pass same timestamp from #2 down to server again, and use to gather query results from #4.
Generate report w/o additional DB hit.
This is the scheme that I have begun to use in any case where I use the Session as temporary storage. But generating a timestamp in JS isn't necessarily secure, and the whole things feels a little... unstructured. Is there an existing design pattern I can use for this, or a more streamlined/secure approach? Any help would be appreciated.
Thanks.
You may take a look at TempData which stores the data in Session.When you pull something out of TempData it will be removed after the Action is done executing.
So, if you put something in TempData in an Action, it will live in TempData across all other actions until its requested TempDatafrom TempData again.
You can also call TempData.Peek("key") which will keep it in memory until you call TempData["key"] or TempData.Remove("key")
Ok, I'm not sure I understand you correctly as the JS timestamp step seems superfluous.
But this is what I would do.
public static string SessionReportKey = "Reports";
public static string ReportIDString = "ReportID";
public Dictionary<string, object> SessionReportData
{
get
{
return Session[SessionReportKey] == null ?
new Dictionary<string, object>() :
(Dictionary<string, object>) Session[SessionReportKey];
}
set
{
Session[SessionReportKey] = value;
}
}
public ActionResult PreviewReport()
{
//retrive your data
object reportData = GetData();
//get identifier
string myGUID = new GUID().ToString();
//might only need [SessionReportData.Add(myGUID, reportData);] here
SessionReportData = SessionReportData.Add(myGUID, reportData);
//in your view make a hyperlink to PrintReport action with a
//query string of [?ReportID=<guidvalue>]
ViewBag[ReportIDString] = myGUID;
return View(reportData);
}
public FileContentResult PrintReport()
{
if(SessionReportData[QueryString[ReportIDString]] == null)
{
//error no report in session
return null;
}
return GenerateFileFromData(SessionReportData[QueryString[ReportIDString]]);
}
I am creating asp.net MVC Application using MVC 3.0. I have 2 users but the DataBase is the same. So, Is it possible to setup two connection strings or even more in web.config? when user login, I redirect it to his database, so then he can use his DataBase.
So major issue here is to find out which user is logged in and use connection string for that user.
I am using default mvc account controller and for example when i want to display welcome message for user in my view i type: if (#User.Identity.Name == "UserName") then some message
So where is the best place to find out which user is logged in and set his connection string in controller or in a view?
Yes, you can have as many connection strings in your web.config file as you want.
But, if you're designing a multi-tenant application than there are better ways of doing it than adding a connection string to web.config file every time a new user signs up.
Probably the best way for you is to have a single database where user-related tables have foreign keys to Users table.
You can learn more about multi-tenant architectures from this Microsoft article.
I agree with Jakub's answer: there are better ways of handling multi-tenancy than having a different database per user.
However, to answer your specific question, there are two options that come to mind:
You can set the connection string to a session variable immediately after login.
Your data access layer can choose the connection string based on the logged in user when it's created. (I'd recommend this over the first option)
To store the connection after login, if you're using the standard ASP.NET MVC Account Controller, look at the LogOn post action:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
//EXAMPLE OF WHERE YOU COULD STORE THE CONNECTION STRING
Session["userConnectionString"] = SomeClass.GetConnectionStringForUser(model.UserName);
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
If you wanted to select the connection string when doing data access, your repository or data access layer will probably have a system for handling that. For instance with Entity Framework Code First, the DbContext constructor allows you to pass in the name of a connection string when you're creating it:
connectionString = SomeClass.GetConnectionStringForUser(model.UserName);
DbContext context = new DbContext(connectionString);
But again, I'd look at other ways of handling multitenancy unless your business dictates that your users have physically separate databases.
you can have multiple connection strings in web.config. Now if you want to use different connection string for different users there must be some criteria for division of users
<appSettings><add key="connectionString" value="Data Source=develope\sqlexpress;Initial Catalog=validation_tdsl;Integrated Security=True;Max Pool Size=1000;Connect Timeout=60000;"></add>
<add key="connectionString1" value="server=MARK\SQLEXPRESS;database=name;integrated security=true;Max Pool Size=1000;Connect Timeout=60000;"></add>
<add key="connectionString2" value="server=name\SQLEXPRESS;database=FM;integrated security=true;Max Pool Size=1000;Connect Timeout=60000;"></add>
and later you can use them like following
Dim con As New SqlConnection(System.Configuration.ConfigurationSettings.AppSettings("connectionString"))
Dim con1 As New SqlConnection(System.Configuration.ConfigurationSettings.AppSettings("connectionString1"))
EDIT : In c# it would be:
SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.AppSettings["connectionString"]);
SqlConnection con1 = new SqlConnection(System.Configuration.ConfigurationManager.AppSettings["connectionString1"])
Note: ConfigurationSettings is now obsolete.