I've seen a project lately using a background worker to make some operations (get data from other web services) and throw the data using events to the client. This project is a WCF service and consume by an ASP.NET web site by another class library as WCF client role and throwing in turn events to the application. This all multithreaded series made me curious to examine. I've seen that this is a basicHttpBinding binding and the only behavior to the service is the UseSynchronizationContext=false where I found out that they added it after unexplained exception which is normal :)
Now I'm asking about the default ConcurrencyMode for the basicHttpBinding. Shouldn't they make it Reentrant or this is the default behavior?
Is this scenario will continue failing cause they already have an unexplained reference not set to an instance of an object if the WCF service is down from the client?
I believe using multithread operations in a WCF service consume by ASP.NET project which relies on IIS handling is bad cause the page could be sent to the client before the WCF service return data to the client class library and append these to the page.
Can you discuss the above and explain your thoughts?
Shouldn't be better when you need such an asynchronous programming style to inform WCF comsumers to notify after long operation using CallbackContracts and embedded WCF technologies, rather multithreading operations?
Need clarification to correct the design and have some proves that this is a bad service architecture, if it is for real, which I suspect!
Thank you.
It is not inherently bad architecture, but it sounds like it does create a number of possible pitfalls.
The WCF client library is leaving all the coordination up to the ASP.NET application. If the ASP.NET app isn't checking that a call to the WCF service has been completed, then it risks using variables before they have been set with values from the service, and other such race conditions unless explicitly setting up some manner of coordinating the initial call against the completion events.
My recommendation would be to rewrite the WCF client asynchronous methods to return Task objects, from the System.Threading.Tasks namespace (MSDN reference). In this way you can spin off the background processing calling the WCF service, and use the Result property of the Task to ensure the service has completed.
An example:
protected void Page_Load(object sender, EventArgs e)
{
Task<string> t = Task<string>.Factory.StartNew(() =>
{
return MyWcfClientClass.StaticAsyncMethod(MyArguments);
}
/* other control initialization stuff here, while the task
and WCF call continue processing in background */
/* Calling Result causes the thread to wait for the task to
complete as necessary, to ensure we have our correct value */
MyLabel1.Text = t.Result;
}
Related
I am using the Spring WebClient (org.springframework.web.reactive.function.client.WebClient) in order to implement some non-blocking behaviour.
Mono<ClientResponse> clientResponse =
webClient
.get(...).exchange();
clientResponse.subscribe((response) -> {
//--- unfortunately my tenant context is lost here !!! Someone knows the right solution?
});
However my tenant-context gets lost once the response arrives (of course, we are in a new thread).
Here is the documentation of how to implement common asynchronous tasks within the tenant-context: https://sap.github.io/cloud-sdk/docs/java/features/multi-tenancy/multi-tenancy-thread-context/
However, I couldn't find the recommended way how to remain the tenant-context using Spring webflux (using the WebClient).
Edit: The SAP Cloud SDK destroys a ThreadContext at the end of an operation. This is done to prevent it from leaking e.g. when the thread is re-used.
If:
the context is passed to an asynchronous operation
but the "parent" operation is done before the asynchronous operation starts
the ThreadContext will not be available in the asynchronous operation. That is what is happening when using the WebClient.
This is not true for custom properties, the SDK does not clear them. But that also means that you have to clear them yourself to ensure they don't leak when the thread is being re-used.
I'd recommend not to use the multi tenancy features of the SDK in such cases. Still, I'll leave my below answer in for context.
You can transfer the SAP Cloud SDK's ThreadContext to any new Thread if and only if you have control:
Before the new Thread is created
The operation that will be run asynchronously that requires the context
Edit: The parent thread (context) still exists
I am not too familiar with WebFlux, but I'll assume that:
clientResponse.subscribe runs in the parent Thread
And the lambda is executed in the asynchronous Thread
Given that, the following should transfer the ThreadContext to be present in the lambda:
ThreadContextExecutor executor = new ThreadContextExecutor();
clientResponse.subscribe((response) ->
executor.execute(() ->
{
// your code goes here, the ThreadContext should be available
}
)
);
You would have to do this at every point where an operation is running in a new Thread. As Artem pointed out, currently there is no feature in the SDK for this that would achieve the same automagically.
I think it is also possible to define a custom ExecutorService that Spring will use to create and run new Threads. In a custom executor you could encapsulate this wrapping logic once for all operations.
The SAP Cloud SDK APIs support Spring Boot and currently don't support Spring Webflux out of the box. You'll probably see all sorts of errors if using the SDK APIs with reactive Spring development. On the other hand, as Matthias showed workarounds might be possible for certain use-cases.
We consider adding Spring WebFlux support in the future. It probably won't happen this year (in 2021).
I am new to WCF web services. My requirement is to create a WCF service which is a wrapper for third-party COM dll object.
Let's assume that the dll takes 5 sec to calculate one particular input.
When I created the service and tested it (using the WCF test client) the scenario I see that I am not able to send 2nd request until first request is completed.
So I was thinking to start a new thread for consuming the com functionality and call a callback function once done. I want to send the response and end request in this callback function.
This is for every request that hits the WCF service.
I have tested this, but problem is I am getting the response without completing the request.
I want current thread to wait until the calculations are done and also accept other requests in parallel
Can you please let me know how I can fix this considering the performance?
My service will be consumed by multiple SAP Portals clients via SAP PI
The concurrencymode for service can be set applying [ServiceBehavior] attribute on Service Class implementing ServiceContract.
http://msdn.microsoft.com/en-us/library/system.servicemodel.concurrencymode(v=vs.110).aspx
However, in your situation where you access a COM component in service operation, I'd first check the Threading model for COM component i.e. does it implement Apartment (STA) or MTA. If COM component implements Apartment threading model, COM call invocation will be serialized. Thus, changing WCF ConcurrencyMode will not have any impact.
HTH,
Amit Bhatia
We have created a WCF RESTful service for a WPF(UI) Application. The UI sends a request to the WCF Service which then invokes a suitable method in BLL, which in turn invokes a method in DAL. All these layers have been separated using IOC/DI.
Now, for a new feature, we want that when a new object of a certain type is added to the database, it should go through 3 steps which would be performed in a separate thread.
That is, if service sends a request to BLL to add a new object OBJ to the database, the BLL should save the object into database through the DAL and then initiate a new thread to perform a some actions upon the object without blocking the WCF Request.
But whenever we try to do so by starting a new thread in the BLL, the application crashes. It is so because the 'InRequestScope' object of the database context has been disposed and the thread cannot update the database. Also the WCF request does not ends until the thread is completed, although the return value has been provided and the BLL method has completed execution.
Any help would be much valued.
I have figured out the solution and explanation for this behavior. Turns out to be a rather silly one.
Since I was creating a thread from the BLL (with IsBackground = true;), the parent thread (originated by the service request) was waiting for this thread to end. And when both the threads ended, the response was sent back to the client. And the solution, well, use a BackgroundWorker instead, no rocket science, just common sense.
And for the disposing of context, since the objects were InRequestScope, and the request had ended. So every time a Repository required a UnitOfWork (uow/context), it would generate a new context and end it as soon as the database request was complete. And the solution would be, create a uow instance, store in a variable, pass it to the repository required to be used, and force all repositories to use the same uow instance than creating a new one for itself.
This seem more of a client-side concern than a service-side concern. Why not have the client make asynchronous requests to WCF service since this automatically provides multi-threaded access to the service.
The built-in System.Net.WebClient (since you're access a webHttpBinding or WCF Web API endpoint) can be used asynchronously. This blog post gives a quick overview of how it is done. Although this MSDN article seems to apply to file I/O, about three quarters down, there is a detailed explanation on coding asynchronous WebClient usage.
I'm using multithreaded wcf maxConcurrentCalls = 10. By logging calls to my service I see that 10 different threads are executing in my service class and that they are reused in the following calls.
Can I tell WCF to destroy/delete a thread so it will create a new one on the next call?
This is because I have thread-static state that I sometimes want to be cleared (on unexpected exceptions). I am using the thread-static scope to gain performance.
WCF doesn't create new threads. It uses threads from a thread pool to service requests. So when a request begins it draws a thread from this pool to execute the request and after it finishes it returns the thread to the pool. The way that WCF uses threads underneath is an implementation detail that you should not rely on. You should never use Thread Static in ASP.NET/WCF to store state.
In ASP.NET you should use HttpContext.Items and in WCF OperationContext to store some state that would be available through the entire request.
Here's a good blog post you may take a look at which illustrates a nice way to abstract this.
Background:
I have a system that hosts WCF services inside a Windows Service with NetTCP binding. To add a new service to the collection you simply add the standard WCF config entries inside <system.serviceModel -> services /> and then add a line inside a custom configuration section that tells the hosting framework it needs to initialize the service. Each service is initialized with its own background thread and AppDomain instance to keep everything isolated.
Here is an example of how the services are initialized:
Host
- ServerManager
- ServiceManager
- BaseServerHost
The ServerManager instance has a collection of ServiceManagers that each correlate to a single service instance which is where the standard WCF implementation lies (ServiceHost.Open/Close, etc). The ServiceManager instance instantiates (based on the config - it has the standard assembly/type definition) an instance of the service by use of the BaseServerHost base class (abstract). Every service must inherit from this for the framework to be able to use it. As part of the initialization process BaseServerHost exposes a couple of events, specifically an UnhandledException event that the owning ServiceManager attaches itself to. (This part is critical in relation to the question below.)
This entire process works exceptionally well for us (one instance is running 63 services) as I can bring someone on who doesn't know anything about WCF and they can create services very quickly.
Question:
The problem I have run into is with background threading. A majority of the exposed methods on our endpoints do a significant amount of activity after a standard insert/update/delete method call such as sending messages to other systems. To keep performance up (the front-end is web-based) we let the initial insert/update/delete method do its thing and then fire off a background thread to handle all the stuff an end-user doesn't need to wait for to complete. This option works great until something in that background thread goes unhandled and brings the entire Windows service down, which I understand is by design (and I'm OK with).
Based on all of my research I have found that there is no way to implement a global try/catch (minus using the hacked config of enabling 1.1 handling of background crashing) so my team will have to go back and get those in the appropriate places. That aside, what I've found is on the endpoint side of the WCF hosting appears to be in its own thread on each call and getting that thread to talk to the "parent" has been a nightmare. From the service viewpoint here is the layout:
Endpoint (svc - inherits from BaseServerHost, mentioned above)
- Business Layer
- Data Layer
When I catch an exception on a background thread in the business layer I bubble it up to the Endpoint instance (which inherits from BaseServerHost) which then attempts to fire BaseServerHost's UnhandledException event for this particular service (which was attached to by the owning ServiceManager that instantiated it). Unfortunately the event handler is no longer there so it does nothing at all. I've tried numerous things to get this to work and thus far all of my efforts have been in vain.
When looking at the full model (shown below), I need to make the Business layer know about its parent Endpoint (this works) and the endpoint needs to know about the running BaseServerHost instance which needs to know about the ServiceManager that is hosting it so the errors can be bubbled up to this for use in our standard logging procedures.
Host
- ServerManager
- ServiceManager <=====================
- BaseServerHost ||
- Endpoint (svc) ||
- Business Layer <======
- Data Layer
I've tried static classes with no luck and even went as far as making ServerManager static and expoting its previously internal collection of ServiceManagers (so they can be shutdown), but that collection is always empty or null too.
Thoughts on making this work?
EDIT: After digging a little further I found an example of exactly how I envision this working. In a standard ASP.NET website, on any page/handler etc. you can use the HttpContext.Current property to access the current context for that request. This is exactly how I would want this to work with a "ServiceManager.Current" returning the owning ServiceManager for that service. Perhaps that helps?
Maybe you should look into doing something with CallContext:
http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.aspx
You can use either SetData/GetData or LogicalSetData/LogicalGetData, depending on whether you want your ServiceManager to be associated with one physical thread (SetData) or a "logical" thread (LogicalSetData). With LogicalSetData you could make the same ServiceManager instance available within a thread as well as within that thread's "child" threads. Will try to post a couple of potentially useful links later when I can find them.
Here is a link to the "Virtual Singleton Pattern" on codeproject.
Here is a link to "Thread Singleton"
Here is a link to "Ambient Context"
All of these ideas are similar. Essentially, you have an object with a static Current property (can be get or get/set). Current puts its value in (and gets it from) the CallContext using either SetData (to associate the "Current" value with the current thread) or LogicalSetData (to associate the "Current" value with the current thread and to flow the value to any "child" threads).
HttpContext is implemented in a similar fashion.
System.Diagnostics.CorrelationManager is another good example that is implemented in a similar fashion.
I think the Ambient Context article does a pretty good job of explaining what you can accomplish with this idea.
Whenever I dicsuss CallContext, I try to also include this link to this entry from Jeffrey Richter's blog.
Ultimately, I'm not sure if any of this will help you or not. One it would be useful would be if you had a multithreaded server application (maybe each request is fulfilled by a thread and multiple requests can be fulfilled at the same time on different threads), you might have a ServiceManager per thread. In that case, you could have a static Current method on ServiceManager that would always return the correct ServiceManager instance for a particular thread because it stores the ServiceManager in the CallContext. Something like this:
public class ServiceManager
{
static string serviceManagerSlot = "ServiceManager";
public static ServiceManager Current
{
get
{
ServiceManager sm = null;
object o = CallContext.GetData(serviceManagerSlot);
if (o == null)
{
o = new ServiceManager();
CallContext.SetData(serviceManagerSlot, o);
}
sm = (ServiceManager)o;
return sm;
}
set
{
CallContext.SetData(serviceManagerSlot, value);
}
}
}
Early in your process, you might configure a ServiceManager for use in the current thread (or current "logical" thread) and then store in the "Current" property:
ServiceManager sm = new ServiceManager(thread specific properties?);
ServiceManager.Current = sm;
Now, whenever you retrieve ServiceManager.Current in your code, it will be the correct ServiceManager for the thread in which you are current executing.
This whole idea might not really be what you want.
From your comment you say that the CallContext data that you try to retrieve in the event of an exception is null. That probably means that exception is being raised and/or caught on a different thread than the thread on which the CallContext data was set. You might try using LogicalSetData to see if that helps.
As I said, I don't know if any of this will help you, but hopefully I have been clear enough (and the examples have also been clear enough) so you can tell if these ideas apply to your situation or not.
Good luck.