So bear with me, i am new at MVC and WCF. I already have a set of services (WCF) that exposes my BLL and I am trying to consume those from my MVC.net web application but i am unsure on how to perform security operations here.
These are my app requirements:
Be able to consume WCF services using different credentials for every user on the web application
My BLL (WCF) needs to know what consumer is calling it (right now I only have the MVC app but i am planning to add iOS and Andriod calls to it, so later on i will add REST services to the WCF endpoints) Is there any design pattern for this out there? (or should i just use the soap header to include the caller ID? should i use some sort of caller secret or something?)
I need a security mechanism like Tokens or something so I dont have to pass the username and password on every call of the service method (WCF)
What i have so far:
WCF uses a certificate and and with a custom username validator.
I have manually coded proxies using the contract interfaces instead of generated proxies: But I hate the fact that i have to validate username and password every time a call is made to a WCF service. How in heaven can i use Tokens here? like to know if a given token sent on the soap header is valid or not yet expired? i have searched a lot and no tutorial/code/example is clear enough for me to actually start coding that ;(
I am trying to cache the ChannelFactory but should I? i mean, i will need to cache a channer factory per logged in user per contract ;( is that ok? what can i do here?
Thanks in advance!
Should you cache the ChannelFactory per user per contract?
It depends. There are a couple of considerations. Instantiating a channel factory could take up to 70ms. If you are doing this repeatedly, you will see a noticeable performance hit if you are not caching the ChannelFactory and instantiating one (or more) each time a user makes a http request to your MVC app that results in controller actions calling web services. This would indicate that caching the channelFactory would be beneficial for speed.
On the other hand, depending on the number of users you have, if you are caching a lot of channel factories (in a static dictionary for example), you are going to start to use a non-trivial amount of memory - this may become an issue for you.
You have to decide if the cost of instantiating channel factories on the fly (and correctly closing / aborting them and their contained channels) is too high a price vs increasing memory utilisation in the application pool hosting your MVC app.
Either way, I strongly advise to profile your app before you deploy to production.
Related
What would be the best application design when there are multiple clients (companies) working with ASP.NET Core application and a separate instance of HttpClient with the corresponding client certificate must be maintained in ASP.NET application for each of these companies?
First, some important facts about the application:
It's an ASP.NET Core 3.1 application.
Each company using this ASP.NET Core application needs first to upload its own client certificate
during the registration. Certificate and corresponding password are
stored in the database. Certificate is necessary for communication
with some external web service which must be notified on behalf of
the company that some action was performed by the company in the
mentioned ASP.NET Core application. In other words, for some actions
company performs in the ASP.NET Core application, some external web
service must be notified with POST method and corresponding body and
its response must be processed and returned.
After registration,
company can start sending requests to the mentioned ASP.NET Core
application. This ASP.NET Core application should obtain
corresponding company certificate from the database, create
HttpClient object and add certificate to it, prepare request data and call external web service for
notification. Then response from this external web service should be
processed and returned as response to the original company request.
Of course, there can be simultaneous requests coming from different companies, but there can also be simultaneous requests coming for the same company from different company offices - all requests from the same company use the same company client certificate, but request data (body) to notify external web service will always be different.
As far as I know, it's not the best practice to create new HttpClient object for every call to external web service. I have considered HttpClientFactory, but in my case each HttpClient object must contain corresponding client certificate for the company. I know ASP.NET Core supports named HttpClient to maintain separate HttpClient for each company, but AFAIK this named clients can only be created in the Startup class. This won't be sufficient because new company can be registered anytime while ASP.NET app is running, company can upload new certificate while app is running rendering existing named client invalid, etc.
I am considering maintaining a static list containing one HttpClient object for each company. When first request for the company is initiated, new HttpClient is created with the corresponding client certificate and added to this list. For all subsequent requests from the same company (or office) the corresponding HttpClient is obtained from the mentioned static list and reused. Of course, I would have to establish some locking on the company's HttpClient instance so that it does not break in case of simultaneous requests from the same company. One concern I have with this design is that there might be couple of hundred companies and this list of http clients can be quite long.
Do you have any other idea or proposal?
I am considering maintaining a static list containing one HttpClient object for each company.
At a high level I think single-instance-per-company is the right approach, but the devil's in the (implementation) details.
Of course, I would have to establish some locking..
Not if you're using a type that was built for this kind of usage. ConcurrentDictionary, and specifically its GetOrAdd method, will give you a keyed storage mechanism where items are created lazily and is thread-safe and lock-free.
One concern I have with this design is that there might be couple of hundred companies and this list of http clients can be quite long.
I don't know if there's a specific number where you need to start worrying (depends on the OS and hardware, I believe), but at least according to the article that made the HttpClient singleton advice famous, it's in the thousands, not hundreds.
"In the production scenario I had the number of sockets was averaging around 4000, and at peak would exceed 5000, effectively crushing the available resources on the server, which then caused services to fall over. After implementing the change, the sockets in use dropped from an average of more than 4000 to being consistently less than 400, and usually around 100."
Still, if this is a concern, one thing you could do to mitigate it is allow those cached HttpClient instances to expire occasionally. (This should also mitigate that other famous problem.) Unfortunately, ConcurrentDictionary doesn't provide that capability out of the box. MemoryCache does, but doesn't directly support the lazy GetOrAdd semantics like ConcurrentDictionary. For the best of both worlds, have a look at LazyCache.
I am migrating a web service to WCF so I can use binary encoding. I am now realizing that the session calls and application state calls are not recognized. WCF is supposed to be better then a web service so I am assuming that there is a better way to do things.
1) How do I maintain session and call a web service that uses session?
2) How do I replace the application object?
For those of you who are migrating a large project and cannot afford to be so ideological, I found a real answer here:
http://megakemp.wordpress.com/2008/11/27/migrating-aspnet-web-services-to-wcf/
In WCF, the best practice is not to have any state whenever possible, since your clients should be calling you with a "per-call" approach - each call from a client gets a new instance of your WCF service class, which is totally independent of anything else, ideally.
If you need to have persistent state, store it in a persistent store - typically a database.
WCF is also by default totally independent of ASP.NET and IIS, and thus cannot leverage the HttpContext, HttpSessionState and so forth objects - since it might be self-hosted in a console app which has no knowledge of IIS, HTTP context etc.
The question is: what exactly do you really use from those HttpSessionState and HttpApplicationState objects? Somehow, you need to abstract that away or solve it some other way, e.g. have the client send you that information (as a parameter on your web service method call, or as a header in the message), or have the client send you a "token" of sorts which allows you to retrieve the relevant info from e.g. a database table.
Chapter 4 in Juval Lowy's excellent Programming WCF Services (link) is all about Instance Management. There are sections on Per-Session services and Durable services, each of which might be what you're looking for.
However, Marc's point is very valid. There are a lot of cons to using session with WCF services, but it is possible. Lowy discusses a lot of this in some detail.
Ok, Im really going to show my stupidity regarding the ASP.NET security model here but here goes.
I have a WCF web service and I have managed to hack my way around to having it pipe through my custom membership provider.
My membership provider overrides "ValidateUser" in which I attempt to load a user object with data from our SQL server instance. All good so far, I retrieve the creds, load the users object and return true if I don't hit any bumps in the road.
At this point, I would usually stuff the user object (or id) into session or actually just some state bag that's accessible for the lifetime of the request. The problem that I am hitting is that HttpContext is null at this point, even though Im using ASP compatability attributes.
What other options do I have at hand?
Cheers, Chris.
EDIT:
Just to clarify what I want to do. I want to pass user credentials to be authenticated on the server, and once this has happened I would like to keep the the details of the authenticated user somewhere that I can access for the lifetime of the service request only. This would be the equiv of Http.Current.Items?
Is there any object that is instantiated per-request that I can access globally via a static property (i.e. in a similar way to HttpContext.Current)? I assumed that OperationContext was the this, but this is also null?
Can this really be such an uncommon problem? Send creds > retrieve user > stuff user somewhere for access throughout processing the request. Seems pretty common to me, what am I missing?
Cheers, Chris.
Basically, with WCF, the preferred best practice solution is to use per-call activation, e.g. each new request / call gets a new instance of the service class, and all the necessary steps like authentication and authorization are done for each request.
This may sound inefficient, but web apps, and in particular web services, ought to be totally stateless whenever possible. Putting stuff in a "state bag" just calls for problems further down the road - how do you know when to invalidate that cached copy of the credentials? What if the user exists your app but the cookie stays on his machine?
All in all, I would strongly suggest trying to get used to the idea of doing these step each and every time. Yes, it costs a little bit of processing time - but on the other hand, you can save yourself from a lot of grief in terms of state management in an inherently stateless environment - always a kludge, no matter how you look at it....
If you still insist on that kludge, you can turn on an ASP.NET "compabitility" mode for WCF which should give you access to HttpContext - but again: I would strongly recommend against it. The first and most obvious limitation is that this ASP.NET compatibility mode of course only works when hosting your WCF service in IIS - which I would again rather not do in production code myself.
To turn on the ASP.NET compatibility mode, use this setting in web.config:
<system.serviceModel>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
and you need to decorate your service implementation (the class implementing the service contract) with a corresponding attribute:
[AspNetCompatibilityRequirements(RequirementsMode=
AspNetCompatibilityRequirementsMode.Allowed)]
class YourService : IYourService
The AspNetCompatibilityRequirementsMode can be NotAllowed, Allowed or Required.
For more information and a more thorough explanation, see Wenlong Dong's blog post on ASP.NET Compatibility Mode
When working with WCF services, is it better to create a new instance of the service every time you use it? Or is it better to create one and re-use it? Why is either approach better? Is it the same for asynchronous proxies?
Or is it better to create one and re-use it?
Do not start to implement your own pooling implementation. That has already been done in the framework. A WCF proxy uses cached channels factories underneath. Therefore, creating new proxies is not overly expensive (but see Guy Starbuck's reply regarding sessions and security!).
Also be aware that a proxy times out after a certain idle time (10mins by default).
If you want more explicit control you might consider using ChannelFactories and channels directly instead of the "easy to go, full out of the box" ClientBase proxies.
http://msdn.microsoft.com/en-us/library/ms734681.aspx
And a "must read" regarding this topic is:
http://blogs.msdn.com/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx
in addition to the things Guy Starbuck mentioned a key factor would be the security model you're using (in conjunction with the session requirements) - if you don't re-use your proxy, you can't re-use a security sessions.
This means that the client would have to authenticate itself with each call which is wasteful.
If, however, you decide this is what you wish to do, make sure to configure the client to not establish a security context (as you will never use it), this will save you a couple of roundtrips to the server :-)
One more point to consider is channel faults. By design WCF does not allow to use client proxy after unhandled exception happened.
IMyContract proxy = new MyContractClient( );
try
{
proxy.MyMethod( );
}
catch
{}
//Throws CommunicationObjectFaultedException
proxy.MyMethod( );
There is a corollary here to Server Activated Objects in .NET Remoting (one of the technologies that is replaced by WCF), which have two modes, "Single Call" (stateless) and "Singleton" (stateful).
The approach you take in WCF should be based on your performance and scaling requirements in conjunction with the needs of your consumers, as well as server-side design constraints.
If you have to maintain state between calls to the service, then you will obviously want to have a stateful instance, but if you don't you should probably implement it so that it is static, which should scale better (you can more easily load balance, etc).
I have been working on splitting up the app tier and web tier of a web application. In the app tier, I managed to separate the business logic into a bunch of services exposed using WCF proxies. The problem is that these services talk to another legacy application that uses a large CLR object as its primary means of communication. To keep things quick, I had been keeping a copy of this object in the session after I created it the first time. Now I know that WCF can do sessions, but the session storage is per service whereas my business logic is now split into multiple services (as it should be).
Now the questions:
Is there a way to share session storage between WCF services hosted on the same host?
Is this even something I should be doing?
If not, then what are the best practices here?
This is probably not the first time somebody’s had a large business object on the server. Unfortunately for me, I really do need to cache this object per user (hence the session).
It’s possible the answer is obvious and I'm just not seeing it. Help please!
I think instance context sharing can help
http://msdn.microsoft.com/en-us/library/aa354514.aspx
As far as I understand WCF, it is designed to be as stateless as it could be. In a session you can remember some values in your service, but objects are not meant to live outside the scope of a session.
Therefore, I'd think you are in trouble.
Of course, there might be some way to store and exchange objects between sessions that I don't know (I use WCF, but I don't know very much about it, apart from what I need for myself).
(if there is a way to share objects between services, it probably would only work on services you host yourself. IIS hosting might recycle your service sometimes)
Perhaps you can wrap this object in a singleton service. This is a service with only one instance, which will not be destroyed between calls. Because you need an object for each user, this service has to manage a list of them and the calling services has to provide the needed authentication data (or sessionid). Don't forget a timeout to get rid of unneeded objects...
Create a facade service which hosts the large CLR object on behalf of the other app tier services. It can work as an adapter, allowing more specific session identifiers to the more advanced app tier services you have created. The facade can provide a session identifier, like a GUID, which your app tier services can use to get re-connected with the large CLR object.
This provides a few advantages:
Some of your app tier might not need to know about the CLR object at all. They only communicate with the remote facade.
the 'large CLR object' host retains the session object on behalf of the other services who can now share it.
The app tiers now have a facade through which they talk to the legacy service. As you work to refactor this legacy service, the app tier doesn't have to change.
Depending on your setup, you may be able to host the facade via in proc hosting which will give retain performance boost you are seeking.
Breaking things up into subservices seems like a good idea if you want to be able to spread the app out over a farm. However, it's important to keep in mind that whenever an object crosses the appdomain boundary at the vary least it will have to be copied in memory.
It all depends on how big the object is and what kind of data it holds.
If you don't want to pass the object because it's too large you may want to make a query API for the service which receives it. In this way you could manipulate that object without having to do expensive serialization or remoting.
Keep it simple. Since you already have access to Session in your WCF, you can use the SessionID from there. Now:
Create a static dictionary somewhere, where the Key is your sessionId and the value is the business object you want to store.
Instead of accessing the business object in session, just access the sessionid and get the business object from the Value of your dictionary.
(You can also use some type of caching if you wish, for example System.Web.Caching, that way you don't have to cleanup the dictionary manually)