Web API - Class variables retained across requests in class inheriting AuthorizeAttribute - asp.net

I'm trying to implement custom AuthorizeAttribute. In the sample code below, when entering the IsAuthorized method, the variable moduleId retains the value of the last request. I was expecting a separate object for each request and hence the value should be null.
Public Class MyAuthorizeAttribute
Inherits AuthorizeAttribute
Private moduleId As String 'This is variable has previous requests value
Protected Overrides Function IsAuthorized(actionContext As HttpActionContext) As Boolean
moduleId = actionContext.RequestContext.RouteData.Values("moduleId")
'check if user has access to module
Return True
End Function
End Class
On AppStart the custom authorize attribute is applied to all api requests.
Public Sub Register(ByVal config As HttpConfiguration)
config.Filters.Add(New MyAuthorizeAttribute())
End Sub
The same behaviour is experienced for custom ActionFilterAttribute as well.
My question is,
Why is this happening?
Will this impact when there are hundreds of simultaneous requests? If yes, how could I overcome this?
Thanks in advance!

Same filter instance is used for all requests, so you cannot use property.
Instead, you want to use local variable.
Dim moduleId As String = actionContext.RequestContext.RouteData.Values("moduleId")

Related

Not able to access class level private variables from different methods/functions of the same class

In the following I am trying to define a Private variable on Class level called _p. The HTTP.POST for Index will bring a User provided value which I'll set this private variable with. In the second Method called ListOfVehicles, I'll be accessing this variable.
Now everything is alright theoretically, however when I try to access this private variable I don't get anything, this is found Nothing.
Public Class QuotationController
Inherits System.Web.Mvc.Controller
'Private Variables
Dim _p As String
'Get Basic pickup and dropoff details
Function Index() As ActionResult
Return View()
End Function
'Function to get basic details out of the view
'and to redirect to ListOfVehicles
<HttpPost()>
Function Index(ByVal P As String, ByVal D As String) As ActionResult
_p = P
Return RedirectToAction("ListOfVehicles")
End Function
'Show list of vehicels
Function ListofVehicles() As ActionResult
ViewData("UserChoice") = "Pickup: " & _p
vehicleList = QB.GetQuotation(_p, _d)
Return View(vehicleList)
End Function
End Class
That is fundamentally impossible.
Each HTTP request gets a separate controller instance; they don't share anything.
You should use cookies, session, application state, or cache, as appropriate.
In your case, you should probably include that variable in a POST to the other action from a <form>.
If you don't want to add a formal post parameter you can use
TempData.Add("P", P);
just before the return statement, in your ListOfVeicles you can accesso via
string p = TempData["P"];
Temp data is valid just within the request scope
EDIT: sorry for C# syntax, I'm not using VB since the good old days ov VB 6

The right method of sharing database variables (asp.net)

I have been sharing database variables using the following code:
Namespace DataAccessVariables
Public Class Vars
Public Shared s As String
Public Shared con As String = WebConfigurationManager.ConnectionStrings("Dev").ToString()
Public Shared c As New SqlConnection(con)
Public Shared x As New SqlCommand(s, c)
End Class
End Namespace
I then import this to my project like this:
Imports DataAccessVariables.Vars
When I check the site with FXCop, I get this message:
Error, Certainty 90, for StaticHolderTypesShouldNotHaveConstructors
{
Target : DBVars (IntrospectionTargetType)
Resolution : "Remove the public constructors from 'Vars'."
Help : http://msdn2.microsoft.com/library/ms182169(VS.90).aspx (String)
Category : Microsoft.Design (String)
CheckId : CA1053 (String)
RuleFile : Design Rules (String)
Info : "Instances of types that define only static members
do not need to be created. Many compilers will automatically
add a public default constructor if no constructor
is specified. To prevent this, adding an empty private
constructor may be required."
Created : 2010/04/20 01:25:16 PM (DateTime)
LastSeen : 2010/04/21 07:17:46 AM (DateTime)
Status : Active (MessageStatus)
Fix Category : Breaking (FixCategories)
}
If I remove the 'Public Shared' from the declarations, then the variables are not picked up in my pages. Can anyone show me the correct way of sharing them?
Thanks a lot,
Phil.
This error isn't telling you to remove the Public Shared variables. Instead it's letting you know that it is possible to create a new instance of your Vars class, even though it includes only Shared members. To resolve the issue, define a private constructor:
Private Sub New()
End Sub
This will prevent any code creating an instance of the Vars class outside of the class itself.
Is that the only code in your class?
Also, you should not create a global (static) SqlConnection. Simply create the SqlConnection and SqlCommand objects on-demand. Connection pooling will ensure that only one physical database connection is made at a time.
The way you've got it here, it's not thread-safe (if two people make a request at the same time, for example, things are going to get really screwy).

How to create singleton Page in asp.net

We can use a class implement IHttpHandlerFactory to override or intercept the create progress of Page's instance
In a word we can use:
PageHandlerFactory factory = (PageHandlerFactory)Activator.CreateInstance(typeof(PageHandlerFactory), true);
IHttpHandler handler = factory.GetHandler(context, requestType, url, pathTranslated);
return handler;
to create new instance of asp.net page object.
But you know, the page is not in persistence
If you save the object in applicationstate or session, when next request, you can get the page,but you will find the Application(HttpApplication) in "Page.Context" is null.
In that, the page visit will fail and it cannot be a singleton one.
How to set the httpApplication?
I don't understand all of your question, but I guess you are looking for HttpContext.Current.Application
Use that instead of Page.Context.Application.
I think that you need to call the internal protected FrameworkInitialize() function after the page has been constructed.

fluent nhibernate Exception error

am trying to implement fluent nhibernate in MVC project...there were no build errors... but when i run the project i get this exception
System.Xml.Schema.XmlSchemaValidationException: The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has incomplete content. List of possible elements expected: 'meta, subselect, cache, synchronize, comment, tuplizer, id, composite-id' in namespace 'urn:nhibernate-mapping-2.2'.
have no idea what am doing wrong here... the following is the code for opening session factory...
Private Function CreateSessionFactory() As ISessionFactory
Dim sessionFactoryObject As ISessionFactory
sessionFactoryObject = Fluently.Configure().Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.ConnectionString("Data Source=.\sqlexpress;Initial Catalog=Designs;User ID=sa;Password=root")).Mappings(Function(x) x.FluentMappings.Add(GetType(DesignMap))).BuildSessionFactory()
Return sessionFactoryObject
End Function
this is really driving me nuts....thanks in advance...:)
update-the mappings
the design table map
Public Class DesignMap
Inherits ClassMap(Of Design)
Public Sub DesignMap()
Table("DesignList")
Id(Function(x) x.DesignId)
Map(Function(x) x.DesignType)
References(Function(x) x.Designer, "DesignerId")
End Sub
End Class
the designer table map
Public Class DesignerMap
Inherits ClassMap(Of Designer)
Public Sub DesignerMap()
Table("DesignerList")
Id(Function(x) x.DesignerId)
Map(Function(x) x.DesignerName)
Map(Function(x) x.DesignerCompany)
HasMany(Function(x) x.DesignersDesigns)
End Sub
End Class
new edit-- the entity property looks like this
Public Overridable Property Name() As String
Get
Return _name
End Get
Protected Set(ByVal value As String)
_name = value
End Set
End Property
am i going the right way..?
I'm not quite sure as the mappings seem ok. I can see one error tough, you have only mapped one of your classes:
.Mappings(Function(x) x.FluentMappings.Add(GetType(DesignMap)))
That should not cause this type of error tough. If you add both your mappings and call the method .ExportTo(#"C:\your\export\path") you will get the actual xml mappings. This way it's easier to see the error. You can do that like this:
.Mappings(Function(x) x.FluentMappings.Add(GetType(DesignMap)).Add(GetType(DesignerMap
).ExportTo(#"C:\your\export\path"))
You can also use the method AddFromAssemblyOf (or some other. There is a few choices) if you don't want to add the mappings one by one.
Try exporting the mappings and see if you can find any error. Or you can post the xml mappings and someone else might find something.
There are several things that can cause this. When using automappings, you will get this if you incorrectly specify the assemblies and namespaces to look in. Other things (more likely in your case) that could cause it, are entity properties that aren't marked as public virtual, having an entity constructor with arguments, but neglecting to make a default constructor, or inheriting your entities from a base class.
I would probably first check to make sure all of your entity properties are "public virtual".
found the problem...the constructor for the map was wrong...it should be like this...
Public Class DesignMap
Inherits ClassMap(Of Design)
Public Sub New()
Table("DesignList")
Id(Function(x) x.DesignId)
Map(Function(x) x.DesignType)
References(Function(x) x.Designer, "DesignerId")
End Sub
End Class
problems of working in both C# and vb.net at the same time i guess..!!
and "Matthew Talbert" was correct...making all the properties Overrideable is important..
thanks guys...:)

Extend System.Web.HttpContext.User

I would like to extend the System.Web.HttpContext.User object (ASP.NET/VB.NET) so that it contains other fields besides just Name. I understand I can create an object that inherits the System.Security.Principal.GenericPrincipal class, but how do I store that in the Current.User object in a usable fashion. ie, I can do something like Current.User.UserID.
So far to achieve this I've created a kludgy workaround by using | delimited strings in the User.Name property and then splitting them, but it's getting kind of ridiculous.
Any suggestions?
Thanks!
EDIT: I have tried the following to no avail:
Imports System.Security.Principal
Public Class CurrentUser : Inherits GenericPrincipal
Private _totalpoints As Integer
Private _sentencecount As Integer
Private _probationuntil As DateTime
Public ReadOnly Property TotalPoints() As Integer
Get
Return _totalpoints
End Get
End Property
Public ReadOnly Property SentenceCount() As Integer
Get
Return _sentencecount
End Get
End Property
Public ReadOnly Property ProbationUntil() As DateTime
Get
Return _probationuntil
End Get
End Property
Public Sub New(ByVal principle As IIdentity, ByVal roles() As String, _
ByVal points As Integer, ByVal sentences As Integer, ByVal probationTil As DateTime)
MyBase.New(principle, roles)
_totalpoints = points
_sentencecount = sentences
_probationuntil = FixDBNull(probationTil)
End Sub
End Class
setting the object in my Global.asax Application_AuthenticateRequest function like so:
HttpContext.Current.User = New CurrentUser(User, userRoles, _
points, sentenceCount, probationUntil)
with a direct cast wherever the object is needed like so:
Dim thisUser As CurrentUser = DirectCast(Current.User, CurrentUser)
i also tried CType and it didn't work... my error is
[InvalidCastException: Unable to cast object of type 'System.Security.Principal.GenericPrincipal' to type 'myProject.CurrentUser'.]
i'm losing my mind here ... :( thanks guys...
anyone?
You can create your own Principal class with the required properties, that inherits from a Generic Principal, and then set the User property of your Current Context to be the a user of that type.
The example below is for ASP.Net MVC but a similar approach could be used with webforms.
You can do this in the PostAuthenticateRequest after a user is authenticated (in the Global.asax)
private void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
SomePrincipal newUser = new SomePrincipal(User.Identity, tmpRoles);
senderRef.Context.User = newUser;
System.Threading.Thread.CurrentPrincipal = newUser;
}
You could then add a property or method in a base class of your page (or controller) for example that to wrap and type the Context.User principal to your Principal type and make sure you call it rather than calling the one on the HttpContext.
There are probably other solutions too!
Would this approach work for you? It looks a little involved but it really doesn't take too long to setup:
Create a 'base' class of your own, and have your pages inherit from that. For example, create a base class called 'BasePage' which inherits from System.Web.UI.Page.
Have your ASP.net pages inherit from your new BasePage class.
In the BasePage class, you can have a public property which contains the extra fields you want to store for your user (eg. BasePage.FirstName, BasePage.LastName). Better still, create a User object containing the extra fields, and expose that via BasePage, eg. "BasePage.Customer". This keeps things tidy if you plan to extend BasePage later.
You can then override the OnInit() of the base class to check for HTTPContext.Current.User.Name property, and fetch the necessary info from your DB to initialise your custom properties.
You can modify the code so that it won't need to hit the database each time the page is refreshed by using ControlState to check whether the custom fields have values before populating them again from the database.
Hope this helps...
Richard.

Resources