I am new to .NET programming and I am trying to implement sessions in my already screwed sample. So here are the details of my sample i had done till now.
I have types of solutions in my project. A Class library, web application and console application.
I created a static class which has a bunch of get/properties and using these properties as global variables to use in my Class library. These get/set properties have a mixed set of data structures like list and dictionaries.
My Web app has only one page with a bunch of list boxes and button. I am using all the get set properties from my class library in to my Web application for some data storing and retrieving purposes. Now when the web page is opened in two different browsers then the data is over written from one user to the other as I am using all static variables and storing data in those static variables.
My best solution to this is using sessions but I am a little confused of using them in my project. Can any one please help me in this regard.
Here is a small sample of my explanation:
a XMLData Class in Class Library has a bunch of these get/set properties.
public Dictionary<string, List<string>> Content
{
get { return _testContent; }
set { _testContent = value;}
}
Now how do I use HttpContext Sessions to use in my Class Library to move these static properties to sessions so that every user who uses my site have their set of data. FYI. The web project is basically used for call in methods to the class library and do a little selection on the list box of the UI which are kind of inputs to my test.
Thanks In Advance.
The simple way is that you can access the current context in a class in your class library using
HttpContext.Current
this has Session available on it.
There are more complex ways that your application could be architected, but we'll start with the simplest :)
To elaborate, your class library may declare an interface for a component that is able to access session
public interface ISessionStore
{
object Get(string key);
void Save(string key, object value);
}
now, define a concrete implementation of ISessionStore
public class HttpContextSessionStore : ISessionStore
{
public object Get(string key)
{
var context = HttpContext.Current;
if (context == null)
throw new InvalidOperationException("this class is intended to work only within web applications");
return context.Session(key);
}
public void Save(string key, object value)
{
var context = HttpContext.Current;
if (context == null)
throw new InvalidOperationException("this class is intended to work only within web applications");
// note that this will overwrite anything already set
// against this key in session
context.Session[key] = value;
}
}
Now you can program against the interface ISessionStore and use the HttpContextSessionStore in your application.
I'd recommend looking at the MVP pattern if you're working with web forms or alternatively, take a look at the MVC framework.
In addition to Russ Cam's comments above, you should also check that HttpContext.Current != null in methods in your class library. It's guaranteed to bite you in the ass if you start writing unit tests, or for any code which isn't being executed within ASP.Net
Related
So I created a class to hold user settings and i'm saving it as a JSON string so that I can modify it whenever I please without doing migrations every time I add one setting.
Anyways everything is working wonderful, well until, exception, I look further into it, and I've found things about it being thread safe but I don't really understand what they mean, how is my simple function that accesses entity identity dbcontext, not thread safe?
public static AppUserSettings GetUserSettings(this IIdentity identity)
{
var user = IdentityDbContext.Users.Find(identity.GetUserId());
return user.SettingsClass != null ? JsonConvert.DeserializeObject<AppUserSettings>(user.SettingsClass) : new AppUserSettings();
}
and the sister function:
public static void SetUserSettings(this IIdentity identity, AppUserSettings toSaveUserSettings)
{
var user = IdentityDbContext.Users.Find(identity.GetUserId());
user.SettingsClass = JsonConvert.SerializeObject(toSaveUserSettings);
DatabaseUtil.SaveChanges(IdentityDbContext);
}
Any help is appreciated, if need be I can attach other classes and/or snippets, but I feel like it is largely a Identity/Entity issue.
I'm trying to implement the Identity system in an ASP.NET Core app (RC2 libraries) and there is a particular hangup that is driving me crazy.
First of all, I am not using EntityFramework. I'm not even using SQL. I'm backing up to RavenDB, so I need the implementation to be very specific to that; Which isn't a problem.
So I designed a RavenUserStore class, and it looks like this;
public class RavenUserStore<TUser> :
IUserStore<TUser>,
IUserLoginStore<TUser>,
IUserPasswordStore<TUser>,
IUserRoleStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserClaimStore<TUser>,
IUserLockoutStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserEmailStore<TUser> {
// ...
}
Works great on its own. I've implemented all the methods, etc. It's wonderful. Very clean and efficient.
Now, I go over to my web application and wire things up;
services.AddTransient<ILookupNormalizer>(s => new LowerInvariantLookupNormalizer());
services.AddTransient<IPasswordHasher<Member>>(s => new PasswordHasher<Member>());
services.AddTransient<IUserStore<Member>, RavenUserStore<Member>>();
services.AddIdentity<Member, Role>(o => {
o.Password.RequiredLength = 6;
o.Password.RequireDigit = true;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
})
.AddUserStore<RavenUserStore<Member>>()
.AddRoleStore<RavenRoleStore<Role>>();
So I go make a controller to use this, per all the samples I've seen, and the very core sample from the Identity Framework Github Repository
//... [PROPERTIES]...//
public AccountController(UserManager<Member> userManager, SignInManager<Member> signInManager) {
// ... [attach constructor parameters to properties] ...//
}
Alright, so I inspect the classes carefully.
UserManager<T> has a property Store,which is a type of IUserStore<T>.
So theoretically.. if the dependency injection resolves types of IUserStore<T> to RavenUserStore<T> when they are injected through a constructor.. shouldn't that mean that the UserManager<T> gets a RavenUserStore<T> as its Store property?
I thought it would too; But when I call methods on the UserManager, it DOES NOT call the ones on my RavenUserStore. Why is this? What can I do?
Do I really have to ALSO make a custom UserManager class and do all of those methods AGAIN?
You need to add your own custom providers before calling services.AddIdentity(). Internally, AddIdentity uses TryAddScoped() which only adds the default items if they don't already exist in the services container.
So just putting the call to AddIdentity() after you registered all your custom implementations should mean that they will take precedence as you expect.
I am new to Web Technology. I have a WebService called Sample. It references a dll with name Custom.dll. My WebMethod is returning a class from Custom.dll which is marked as Serialization.
// My custom class
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://somthing-something.mydomain.com/")]
public class CustomClass
{
public string id;
public string key;
}
// My Web Service method
[WebMethod]
public CustomClass MyWsMethod()
{
return new CustomClass{id="id", key="Key"};
}
Also to mention, my webservice is a WCF Service and has a asmx file in it.
I am consuming this webservice in my application and service referenced my webservice as localhostWS. My Application also references Custom.dll. When I am calling my webservice method then I am not able to get back the Custom.CustomClass object. I am returning localhostWS.CustomClass and also I am not able cast it to Custom.CustomClass.
CustomClass custom = localhostWS.MyWsMethod();
Here custom object is of type localhostWS.CustomClass but I was expecting Custom.CustomClass.
Can any body suggest me whats happening here. Please let know if I need to provide any further information. I have tried enough to be clear in my question.
Edit
I must also mention this, it will great to achieve this without changing any Client side code. Due to reasons it will not be possible to change that. However any suggestions are welcome.
I have:
MyNameSpace.MyClass1
MyNameSpace.MyClass2
i need to get value from MyClass1.myvar1 from MyClass2.
Should I do that with static variable
What happens with variable value if it is static in a web application.
Im using MyClass1 as: var mClass=new MyNameSpace.MyClass1(), and from that im using mClass.
thank you
No, you should not use a static variable here. Remember, static means the variable is global for the application. In ASP.Net, you have a single application instance that is shared among everyone who visits your site. Using static variables can result in one user seeing another user's data.
If the value context is global, than it is ok to use static variable. Remember that if the value is updated, its updated for all users. If the data is different or belong to a user, than never use static, instead instantiate object of MyClass1 inside MyClass2 method .
you can use following approach.
Declare MyClass1.myvar1 as public and access from MyClass2.
class MyClass1{
public int myvar1 = 7;
}
class MyClass2{
public void TestMethod(){
MyClass1 obj = new MyClass1();
int val = obj.myvar1;
}
}
In this case, your data is safe.
It is not OK to use a static variable within ASP.NET unless you take thread safety into account. A single request will generally run on a single thread. Different requests will probably run on different threads. (See http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx for some good threading information.)
Unless you study up on writing thread safe code, I would consider using the following objects instead to maintain static data:
Application - for application-wide static data
Session - if it's user specific static data
HttpContext.Items - if it's data to be used by different objects within a single request
HttpRuntime.Cache / HttpContext.Cache - to cache shared data that can have expirations / dependencies
All youneed is to make a new instance of your class2 and call your variable from created instance in class1 like
myclass1
{
string Variable = string.empty;
protected void YourMethod()
{
myclass2 c2 = new myclass2()
this.Variable = c2.Variable;
}
}
i have a HttpModule that creates an CommunityPrincipal (implements IPrincipal interface) object on every request. I want to somehow store the object for every request soo i can get it whenever i need it without having to do a cast or create it again.
Basically i want to mimic the way the FormsAuthenticationModule works.
It assigns the HttpContext.User property an object which implements the IPrincipal interface, on every request.
I somehow want to be able to call etc. HttpContext.MySpecialUser (or MySpecialContext.MySpecialUser - could create static class) which will return my object (the specific type).
I could use a extension method but i dont know how to store the object so it can be accessed during the request.
How can this be achieved ?
Please notice i want to store it as the specific type (CommunityPrincipal - not just as an object).
It should of course only be available for the current request being processed and not shared with all other threads/requests.
Right now i assign my CommunityPrincipal object to the HttpContext.User in the HttpModule, but it requires me to do a cast everytime i need to use properties on the CommunityPrincipal object which isnt defined in the IPrincipal interface.
I'd recommend you stay away from coupling your data to the thread itself. You have no control over how asp.net uses threads now or in the future.
The data is very much tied to the request context so it should be defined, live, and die along with the context. That is just the right place to put it, and instantiating the object in an HttpModule is also appropriate.
The cast really shouldn't be much of a problem, but if you want to get away from that I'd highly recommend an extension method for HttpContext for this... this is exactly the kind of situation that extension methods are designed to handle.
Here is how I'd implement it:
Create a static class to put the extension method:
public static class ContextExtensions
{
public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
{
if(HttpContext.Current.Items["CommunityPrinciple"] != null)
{
return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
}
}
}
In your HttpModule just put the principal into the context items collection like:
HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal);
This keeps the regular context's user property in the natural state so that 3rd party code, framework code, and anything else you write isn't at risk from you having tampered with the normal IPrincipal stroed there. The instance exists only during the user's request for which it is valid. And best of all, the method is available to code as if it were just any regular HttpContext member.... and no cast needed.
Assigning your custom principal to Context.User is correct. Hopefully you're doing it in Application_AuthenticateRequest.
Coming to your question, do you only access the user object from ASPX pages? If so you could implement a custom base page that contains the cast for you.
public class CommunityBasePage : Page
{
new CommunityPrincipal User
{
get { return base.User as CommunityPrincipal; }
}
}
Then make your pages inherit from CommunityBasePage and you'll be able to get to all your properties from this.User.
Since you already storing the object in the HttpContext.User property all you really need to acheive you goal is a Static method that acheives your goal:-
public static class MySpecialContext
{
public static CommunityPrinciple Community
{
get
{
return (CommunityPrinciple)HttpContext.Current.User;
}
}
}
Now you can get the CommunityPrinciple as:-
var x = MySpecialContext.Community;
However it seems a lot of effort to got to avoid:-
var x = (CommunityPrinciple)Context.User;
An alternative would be an Extension method on HttpContext:-
public static class HttpContextExtensions
{
public static CommunityPrinciple GetCommunity(this HttpContext o)
{
return (CommunityPrinciple)o.User;
}
}
The use it:-
var x = Context.GetCommunity();
That's quite tidy but will require you to remember to include the namespace where the extensions class is defined in the using list in each file the needs it.
Edit:
Lets assume for the moment that you have some really good reason why even a cast performed inside called code as above is still unacceptable (BTW, I'd be really interested to understand what circumstance leads you to this conclusion).
Yet another alternative is a ThreadStatic field:-
public class MyModule : IHttpModule
{
[ThreadStatic]
private static CommunityPrinciple _threadCommunity;
public static CommunityPrinciple Community
{
get
{
return _threadCommunity;
}
}
// Place here your original module code but instead of (or as well as) assigning
// the Context.User store in _threadCommunity.
// Also at the appropriate point in the request lifecyle null the _threadCommunity
}
A field decorated with [ThreadStatic] will have one instance of storage per thread. Hence multiple threads can modify and read _threadCommunity but each will operate on their specific instance of the field.