Can Webservices as singletons cause issues with different users? - asp.net

I am developing an ecommerce app that is using the UPS shipping webservice. I have read that it is good to create a singleton so there is only one instance of a webservice at any time. My code for that is below.
Public Class Ship
Private Shared sync As New Object()
Private Shared _Service As New ShipService
Public Shared ReadOnly Property Service As ShipService
Get
If _Service Is Nothing Then
SyncLock sync
If _Service Is Nothing Then
_Service = New ShipService
End If
End SyncLock
End If
Return _Service
End Get
End Property
Public Shared Function GetInstance() As ShipService
Return Service()
End Function
End Class
Here is a snippet from where it will be used.
Public Sub New(ByVal ToAddress As Address, ByVal WeightInLbs As String)
//Not relevant code
Ship.Service.UPSSecurityValue = Security
//More not relevant code
End Sub
Public Function ProcessShipment() As ShipmentResponse
Return Ship.Service.ProcessShipment(ShipmentRequest)
End Function
In the line above in the constructor I have to set the UPSSecurityValue of the service. Then later I will call the ProcessShipment function. My question is; Since the webservice is being traeted as a singleton could different instances of the app share that same UPSSecurityValue and could it change between when I set it and when I call ProcessShipment?

In the case of what you're doing, it could definately change between when you call New and set the Security value and when you actually process the shipment. The singleton is shared across all users of your application (within the same web app, that is - if you had multiple copies of this app on your server, they'd each use their own singleton), so all users will share the same data.
If multiple users run through the application at the same time (or User2 is only 1ms behind):
User1 User2
New (sets security code)
New (sets security code)
ProcessShipment
ProcessShipment
Both shipments will process with User2's security code, which isn't what you want. The way to do this safely could be to pass the security into the function when you ship the package, and then consume it immediately - if you store it for use later, even a single instruction later, you're setting yourself up for a race condition where users read each other's data.

Related

ASP.NET - Async - A system that syncs between two other systems

I am trying to create a system that synchronizes between two other systems' data.
I work on ASP.NET Web Forms using VB (Cannot be changed)
The main system functions will be in a form of Web API which will be triggered by a scheduled task or other events, such as a website form or a landing page.
Each of these functions call a REST API of System 1 and the REST API of System 2 , operates the data, and then calls each system REST APIs to update both sides.
I chose to use a ASP.NET Web Api 2 for the main system, and HttpClient to call the functions.
There will be hundreds of thousands of transactions per day. It is a lot! So I chose to use async/await methods for the HttpClient, (because of the many simultaneous long processing requests), but ASP.NET seems to have forced me to convert all the functions from bottom to top, including the Web Api functions and the database access to Async!
So I ended up changing all the functions to Async and in all the functions that call them I use Await for everything.
Everything seems to work. I don't know if what I did is correct, and I see there is no way to check if my functions are actually working asynchronically.
About the ConfigureAwait(False) I added it because I don't have operations that are context related. If there will be I will remove this statement. I read it is recommended to use it when it is possible. (Am I right?)
SMALL COMMENT:
Why is my solution good??? I am trying to avoid blocking the main thread by creating much more worker threads. Why is this a better solution? I am creating a lot of awaits which each one starts a worker. Isn't it a worse practice than the synchronic solution????
Can somebody tell me if what I am doing is correct and if not - please explain why or if there are other approaches to this scenario?
Here is the code for example (only the relevant parts). A little explanation of what you see:
The WebApi Controller has an Login function
The Login function calls the System1.DoSomething asynchronically
The System1.DoSomething calls the private function
System1.SetCredentials asynchronically
The System1.DoSomething also uses HttpHandler to get data
asynchronically from System1's API
System1.SetCredentials function calls MyLoginManager.GetCredentials asynchronically
MyLoginManager.GetCredentials calls the database asynchronically using DBHelper.ExecuteReaderAsync
The DBHelper.ExecuteReaderAsync function calls ExecuteReaderAsync
asynchronically and also opens the connection asynchronically using
OpenAsync() function
The WebAPI Controller
Public Class WebApiController
Inherits ApiController
Public Async Function Login() As Threading.Tasks.Task(Of IHttpActionResult)
Dim result As MyResult= Await System1.DoSomething().ConfigureAwait(False)
End Function
The System1 Class
Public Class System1
Public Shared Async Function DoSomething() As Task(Of MyResult)
Try
Using client As New HttpClient
client.BaseAddress = New Uri("blablabla")
Await SetCredentials(client).ConfigureAwait(False)
Dim response As HttpResponseMessage = Await client.GetAsync(urlParameters).ConfigureAwait(False)
... More code
End Using
Catch ex As Exception
End Try
End Function
Private Shared Async Function SetCredentials(client As HttpClient) As Task
Dim auth As BasicAuthenticationData = Await MyLoginManager.GetCredentials.ConfigureAwait(False)
Dim credentials As String = Cryptography.EncodeBase64(String.Format("{0}\{1}:{2}", auth.userName, auth.userPassword))
client.DefaultRequestHeaders.Add("Authorization", "Basic " & credentials)
... More code
End Function
End Class
The MyLoginManager Class
Public Class MyLoginManager
Public Shared Async Function GetCredentials() As Threading.Tasks.Task(Of BasicAuthenticationData)
Dim auth As New BasicAuthenticationData
Dim dbConn As String = DBConnection.GetConnection(True)
Dim q As String = "SELECT * FROM BlaBlaBla"
Using sdr As SqlDataReader = Await DBHelper.ExecuteReaderAsync(dbConn, q, Nothing).ConfigureAwait(False)
... More code
End Using
Return auth
End Function
End Class
The DBHelper Class
Public Class DBHelper
Public Shared Async Function ExecuteReaderAsync(ByVal dbConnection As String, ByVal commandText As String, ByVal params() As SqlParameter) As Threading.Tasks.Task(Of SqlDataReader)
Dim dbConnectionAsync As String = New SqlConnectionStringBuilder(dbConnection) With {
.AsynchronousProcessing = True
}.ToString
Dim objConn As New SqlConnection(dbConnectionAsync)
Dim oc As New SqlCommand(commandText, objConn)
Dim sdr As SqlDataReader
' Throws a custom exception if there is a problem
Try
Await oc.Connection.OpenAsync.ConfigureAwait(False)
sdr = Await oc.ExecuteReaderAsync(CommandBehavior.CloseConnection).ConfigureAwait(False)
Return sdr
Catch ex As Exception
End Try
End Function
End Class
You should add a call to ConfigureAwait(false) to any await behind any await that comes out of any controller action.
As Mister Epic said you'll loose things like HttpContext.Current if you call ConfigureAwait(false) and you shouldn't do that on controller action methods. But that also means that every time you don't you incur in context switching.
What you should do is extract the logic in controller action methods to their own methods (preferably on their own class) and pass every thing they need to do their work.
So, the only thing you did wrong was to call ConfigureAwait(false) in the controller action method.
Don't add ConfigureAwait in your web api project. Use it in library code.
The big gotcha is that when you call a method that uses ConfigureAwait, you'll lose your context. Your context includes important details like your session, so you'll need to ensure you capture any details from HttpContext you need before you call into library code that uses ConfigureAwait.

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

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")

How to manage multiple connections for different users

i am working on a CMS solutions for real estate agencies.
so different users/groups will use the same tool.
i created 1 asp.net membership Database where i manage ALL users.
The users are grouped in different roles.( 1 role = 1 agency office)
Then - for every group i have another Database. In this database i manage the real estates and customers of the given office. (These Databases have the same structure.)
Currently i am using the "custom ASP.NET Profile class" where i store the connectionsstring for the specific database. I create this custom profile if the user logs in.
Now i have the problem, if an anonymous user is visiting the page ( there is a public section ) i get connectionstring errors cause there is no "custom profile" where my functions can read the connectionstring
My Custom Profile Class looks like:
Public Class UserProfile
Inherits ProfileBase
Public Shared Function GetUserProfile(username As String) As UserProfile
Return TryCast(Create(username), UserProfile)
End Function
Public Shared Function GetUserProfile() As UserProfile
Return TryCast(Create(Membership.GetUser().UserName), UserProfile)
End Function
<SettingsAllowAnonymous(False)> _
Public Property role() As String
Get
Return TryCast(MyBase.Item("role"), String)
End Get
Set(value As String)
MyBase.Item("role") = value
End Set
End Property
<SettingsAllowAnonymous(False)> _
Public Property UsersCustomConnectionString() As String
Get
Return TryCast(MyBase.Item("UsersCustomConnectionString"), String)
End Get
Set(value As String)
MyBase.Item("UsersCustomConnectionString") = value
End Set
End Property
End Class
Then i can read my connection string like
Dim currentprofile As UserProfile = UserProfile.GetUserProfile()
Dim strcon As String = currentprofile.UsersCustomConnectionString
How could i solve this issue ?
Or should i use another way to solve the "many connection strings" issue ? if yes, how ? (i think session varaiables won't work)
Thanks in advance
This is what we do: put in web.config an entry for each connection string in the
<appSettings>
section like this:
<add key="connection_string_key" value="YourDBServerConnectionString"/>
Then you read the value from your db access class like this:
System.Configuration.ConfigurationManager.AppSettings[connection_string_key]
And if you want to change them dynamically make some factory class where you read them all and return the right connection string based on the role of the current user or if they are logged in or not.

Abstracting HttpContext Request and Session - thread safety

I have the following assemblies in my ASP.NET app:
Website - this is an ASP.NET website
ClassLib - this is just a class lib that contains all the business logic
Class Lib needs to interact with the HttpContext Session and Request objects. This is a code upgrade from an old ASP app, where I've hoovered all the VBScript that contained the logic and put it into VB.NET. We simply didn't have time to rewrite.
Instead of ClassLib interacting directly with HttpContext, which I thought was BAD and also prevented us from unit testing, I introduced the following abstraction layer:
Public Class Request
Private Shared _requestWrapper as IRequestWrapper
Public Shared ReadOnly Property RequestWrapper()
Get
If _requestWrapper Is Nothing Then
Throw New Exception("_requestWrapper is null. Make sure InitRequest() is called with valid parameters")
End If
Return _requestWrapper
End Get
End Property
Public Shared Sub InitRequest(ByRef requestWrapper As IRequestWrapper)
_requestWrapper = requestWrapper
End Sub
Public Shared Function GetVal(ByVal key As String) As Object
Return RequestWrapper.GetVal(key)
End Function
etc.
This means in the unit tests I can supply my own MockRequest object into this Request class, which is just a simple NameValue collection. The code in the ClassLib and the Website then simply use the Request class and are none the wiser that it isn't coming from the HttpContext, but rather this mock class.
When it comes to the real deal, I simply have the following (C#) class:
public class RealRequest : IRequestWrapper
{
public void Initialize(HttpContext context)
{
}
#region Implementation of IRequestWrapper
public object GetVal(string index)
{
return HttpContext.Current.Request[index];
}
etc.
This is initialised in Session_Start of global.asax in the Website, as follows:
protected void Session_Start(object sender, EventArgs e)
{
IRequestWrapper requestWrapper = new RealRequest();
WebSession.Request.InitRequest(ref requestWrapper);
}
I think this is similar to the Static Gateway pattern.
Now, I am aware of singletons and static vars in a multi threaded environment such as ASP.NET, but this is slightly different. When it gets down to the RequestWrapper.GetVal(), its actually going to the HttpContext for that running thread - and pulling the value from that.
Certainly, any concurrent tests that we do with multiple users hitting the same server have never shown up any strange behaviour.
I'm just looking for re-assurance that this is a sound design, and if not why not?
Thanks
Duncan
This is fine. We have a very similar case in our applications that either uses HttpContext if it exists or fake implementations otherwise.
The one thing to watch out for is that there is a very specific instance where HttpContext.Current will return a value but HttpContext.Current.Request will throw an exception when triggered by the Application_Start event. In framework code, you really don't know (or want to know) what triggered the call though.
Workaround for HttpContext.HideRequestResponse being internal? Detect if HttpContext.Request is really available?

Access SQLite from different processes

I'm developing an application that uses SQLite as the primary data storage method. I have two processes running for my app using an alternate entry point.
I need to access the same DB from the two different processes but as we all now SQLite is not like a server DB engine, it can only be accessed once at a time.
I wanted to know if there is a way to kind of "lock" the DB when it's being accessed by other process so that if the second process tries to acces the DB at the same time, it would wait until the first process finishes and then try to access it again.
How can this issue be treated?
If you have not already, create a class that abstracts your database access out and store it in the RuntimeStore. From wherever you are going to interface with SQLite, get a reference to that class using the GUID you stored it with (RuntimeStore.get(long)) and synchronize the class however you would normally (member object lock, synchronized methods).
Do NOT just use the Wikipedia style singleton pattern as it is not a true singleton across processes on this platform.
See:
http://www.blackberry.com/developers/docs/5.0.0api/net/rim/device/api/system/RuntimeStore.html
Sample:
class SQLManager {
private static long GUID = 0xa178d3ce564cae69L; // hash of com.stackoverflow.SQLManager
private SQLManager() {
// ctor stuff here
}
public static SQLManager getInstance() {
RuntimeStore rs = RuntimeStore.getRuntimeStore();
SQLManager instance = rs.get(GUID);
if (instance == null) {
instance = new SQLManager();
rs.put(GUID, instance);
}
return instance;
}
}
You're still using the singleton "pattern" per se, but you're storing the object instance in the RuntimeStore on first getInstance call, and subsequently pulling it form the RuntimeStore - using a GUID that you specify.

Resources