I’m working on a piece of code which would take in an API request to a WebAPI controller and through that invoke a WCF web service. This would block until the WCF service responded and cause issues such as timeouts and performance problems. I can't use async/await for this particular use case for a number of reasons beyond my control.
I’m looking at kicking this WCF call off on a separate thread, so in the WebAPI controller I do something like:
New Thread(()=>{
//Call WCF service here
//Do something with the response
}).Start();
However, the code is blowing up. The line that calls the WCF service was moved into the above codeblock unchanged, but now I’m getting:
Cannot access a disposed object. Object name:
'System.ServiceModel.Channels.ServiceChannel'.
Looking at the stack trace when the exception is thrown, I can see the server stack trace as follows:
Server stack trace: at
System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrImmutable()
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan
timeout) at
System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel
channel, TimeSpan timeout) at
System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan
timeout, CallOnceManager cascade) at
System.ServiceModel.Channels.ServiceChannel.Call(String action,
Boolean oneway, ProxyOperationRuntime operation, Object[] ins,
Object[] outs, TimeSpan timeout) at
System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage
methodCall, ProxyOperationRuntime operation) at
System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage
message)
Im not hugely experienced with WCF so wondered if there was some quirk regarding calling this service in a background thread or if there was something else I needed to do instead?
I’ve tried Googling this but all the results are pertaining to calling a background thread from within a WCF service, not calling a WCF service from a background.
Any ideas?
I am pretty much sure, that you creating instance of WCF service outside thread. So previously it looked like:
using(var client = new WcfServiceClient())
{
client.CallSomeMethod();
}
And you changed it to something like:
using(var client = new WcfServiceClient())
{
new Thread(() => {
client.CallSomeMethod();
}).Start();
}
And what you need to is to move client creation into Thread:
new Thread(() => {
using(var client = new WcfServiceClient())
{
client.CallSomeMethod();
}
}).Start();
}
So I figured this out in the end. It was a Unity problem. For some reason, whereas the existing code was:
container.RegisterType<IMyServiceWrapper, MyServiceImplementation>()
I had to explicitly tell Unity how to resolve the constructor parameter:
container.RegisterType<IMyServiceWrapper, MyServiceImplementation>(
new InjectionConstructor(container.Resolve<IMyDependentService>()));
Unfortunately, I have no idea why this was required or why it fixed it?
Related
I have created a Service Fabric Application. There is a long-running job in the RunAsync() method like "LoadData() which migrates million of records from Database to ServiceFabric dictionary".
As per the MSDN documentation, Services that want to implement a background task, which runs when the service comes up, should override this method with their logic "RunAsync(CancellationToken)"
Cancellation token is used to monitor for cancellation requests and it exists from RunAsync() and shut down the service. So I had used CancellationToken in my project.
Here is my code
RunAsync (System.Threading.CancellationToken cancellationToken);
{
LoadData(CancellationToken);
}
Async Task LoadData(CancellationToken)
{
Method1(CancellationToken) -- Aync call
Method2() -- Normal call
Method3() -- Normal call
}
As you can see, I have Method1, which is an asynchronous call and it runs as a separate thread so the same token is being passed to this method as the main thread will not aware of the child thread.
However, Method2 and Method3 are just functional calls so the CancellationToken is not passed because there are running in the context of the main thread.
I have a couple of questions on CancellationToken usage in Service Fabric.
1. Do we need to pass the CancellationToken for all methods that are being called from the Long-running method( Async/ Sync)?
2. The way how I have handled CancellationToken is correct or Do I need to modify anything?
Do we need to pass the CancellationToken for all methods that are being called from the Long-running method( Async/ Sync)?
Yes, if you are able to respect it. It makes no sense to pass it to a method if it does not do anything with it.
The way how I have handled CancellationToken is correct or Do I need to modify anything?
Hard to tell, we need to know what your code does.
If the service is going to shut down it will use the CancellationToken to cancel any pending work. If you have any async calls that accept a CancellationToken you should pass it to that method so it can exit when cancellation is requested.
If you have some other methods like Method1() and it does some long running work you can still exit when cancellation is requested by either using CancellationToken.IsCancellationRequested or CancellationToken.ThrowIfCancellationRequested. The latter will throw an OperationCanceledException if cancellation is requested.
For example, you can do this:
public void Method1(CancellationToken cancellationToken)
{
// some work
if(cancellationToken.IsCancellationRequested)
return;
// some more work
if (cancellationToken.IsCancellationRequested)
return;
// some more work
}
It is up to you to decide whether the method has some logical points to check for cancellation or that the method is so fast it won't make much difference.
By the way, this is not specific to service fabric, you can find more docs here.
I'm using a Webjob with the Windows Azure Storage SDK. When a new item shows up in a Queue, a method in my class is invoked. According to the SDK docs, if I take a TextWriter as a parameter to my method, the SDK will provide me with a TextWriter that I can write to which will show up in the Webjob's logging infrastructure. This makes it pretty easy to diagnose issues and troubleshoot things.
public async static void ProcessQueueMessage([QueueTrigger("queueName")]MyModelType model, TextWriter logger)
{
await logger.WriteLineAsync(string.Format("Processing Item {0}", model.SasUrl));
// Some work here
await logger.WriteLineAsync(string.Format("Done Processing Item {0}", model.SasUrl));
}
However, very frequently, within the body of my method, the TextWriter is being disposed of. I'm getting the following exception on the 2nd logger.WriteLineAsync:
System.ObjectDisposedException was unhandled by user code
HResult=-2146232798
Message=Cannot write to a closed TextWriter.
Source=mscorlib
ObjectName=""
StackTrace:
at System.IO.__Error.WriterClosed()
at System.IO.StringWriter.Write(Char[] buffer, Int32 index, Int32 count)
at System.IO.TextWriter.WriteLine(String value)
at System.IO.TextWriter.SyncTextWriter.WriteLine(String value)
at System.IO.TextWriter.SyncTextWriter.WriteLineAsync(String value)
at NameOfProject.Program.<ProcessQueueMessage>d__8.MoveNext() in c:\Dev\Path\To\Program.cs:line 173
InnerException:
I can't find others having this problem, so I can't imagine there is a bug in the SDK or webjobs infrastructure.
Is there a way to tell if the logger is disposed of ahead of the call?
Is there a way to create a new logger within my method that will participate in the WebJobs logging subsystems and UI?
That's because your method returns void. Try returning Task instead
I have below application:
Its windows console .NET 3.0 application
I'm creating 20 workloads and assigning them to threadpool to process.
Each thread in ThreadPool creates WCF Client and calls service with request created using workload assigned.
Sometimes on production servers[12 core machines], I get following exception:
There was an error reflecting type 'xyz' while invoking operation using WCF client. This starts appearing in all threads. After sometime it suddenly disappears and starts appearing again.
Code:
Pseudo Code:
for(int i=0;i<20;i++)
{
MultiThreadedProcess proc =new MultThreadedProcess(someData[i]);
ThreadPool.QueueUserWorkItem(proc.CallBack,i);
}
In Class MultiThreadedProcess, I do something like this:
public void Callback(object index)
{
MyServiceClient client = new MyServiceClient();
MyServiceResponse response =client.SomeOperation(new MyServiceRequest(proc.SomeData));
client.close();
//Process Response
}
Can anyone suggest some resolutions for this problem?
If you can turn on diagnostic, appears to me serialization issue, there might be chance that certain data members/values are not able to de-serialized properly for operation call.
I am trying to debug a web service exception. I have both the client and the service running in debug mode in Visual Studio 2010, C#, .net 4.0 framework.
When I run the client, and get it to call the web service, I get an exception:
Type: System.ServiceModel.FaultException`1[[System.ServiceModel.ExceptionDetail, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Error Message: The type initializer for 'myService.Service' threw an exception.
Source: mscorlib
However, the service shows no exceptions whatsoever.
The stack trace that I got seems to indicate that the call was made, and the reply was being handled (even if the reply was an exception):
Server stack trace:
at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Can someone give pointers on what else I need to do to debug this?
I'm currently setting up the Service Trace Viewer tool to see if that will tell me anything more.
The error message suggests that your service class myService.Service has a static constructor or field initializer expression with a bug in it, causing an unhandled exception to escape the static ctor when the Service type is loaded.
In the service host process under the debugger, just put breakpoints on the static ctor and field initializer expressions, and step until the underlying exception occurs.
The Fusion (.NET class loader) Log will likely get you there also, if you know how to use that.
Error is likely a missing dependency on server side. Launch fuslogvw.exe, enable failure logging, reproduce the problem and look for related failure records.
I have a very long running query that takes too long to keep my client connected. I want to make a call into my DomainService, create a new worker thread, then return from the service so that my client can then begin polling to see if the long running query is complete.
The problem I am running into is that since my calling thread is exiting right away, I am getting exceptions thrown when my worker tries to access any entities since the ObjectContext gets disposed when the original thread ends.
Here is how I create the new context and call from my Silverlight client:
MyDomainContext context = new MyDomainContext();
context.SearchAndStore(_myParm, SearchQuery,
p => {
if (p.HasError) { // Do some work and return to start
} // polling the server for completion...
}, null);
The entry method on the server:
[Invoke]
public int SearchAndStore(object parm)
{
Thread t = new Thread(new ParameterizedThreadStart(SearchThread));
t.Start(parms);
return 0;
// Once this method returns, I get ObjectContext already Disposed Exceptions
}
Here is the WorkerProc method that gets called with the new Thread. As soon as I try to iterate through my query1 object, I get the ObjectContext already Disposed exception.
private void WorkerProc(object o)
{
HashSet<long> excludeList = new HashSet<long>();
var query1 = from doc in this.ObjectContext.Documents
join filters in this.ObjectContext.AppliedGlobalFilters
.Where(f => f.FilterId == 1)
on doc.FileExtension equals filters.FilterValue
select doc.FileId;
foreach (long fileId in query1) // Here occurs the exception because the
{ // Object Context is already disposed of.
excludeList.Add(fileId);
}
}
How can I prevent this from happening? Is there a way to create a new context for the new thread? I'm really stuck on this one.
Thanks.
Since you're using WCF RIA. I have to assume that you're implementing two parts:
A WCF Web Service
A Silverlight client which consumes the WCF Service.
So, this means that you have two applications. The service running on IIS, and the Silverlight running on the web browser. These applications have different life cycles.
The silverlight application starts living when it's loaded in the web page, and it dies when the page is closed (or an exception happens). On the other hand (at server side), the WCF Web Service life is quite sort. You application starts living when the service is requested and it dies once the request has finished.
In your case your the server request finishes when the SearchAndStore method finishes. Thus, when this particular method starts ,you create an Thread which starts running on background (in the server), and your method continues the execution, which is more likely to finishes in a couple of lines.
If I'm right, you don't need to do this. You can call your method without using a thread, in theory it does not matter if it takes awhile to respond. this is because the Silvelight application (on the client) won't be waiting. In Silverlight all the operations are asynchronous (this means that they're running in their own thread). Therefore, when you call the service method from the client, you only have to wait until the callback is invoked.
If it's really taking long time, you are more likely to look for a mechanism to keep the connection between your silverlight client and your web server alive for longer. I think by modifying the service configuration.
Here is a sample of what I'm saying:
https://github.com/hmadrigal/CodeSamples/tree/master/wcfria/SampleWebApplication01
In the sample you can see the different times on client and server side. You click the button and have to wait 30 seconds to receive a response from the server.
I hope this helps,
Best regards,
Herber