Multiple webservice call using Parallel.Foreach - c#

I need to process multiple data retrieved from a webservice that only get me single info, like the example below:
List<string> products = GetAllProducts();
List<ProductInfo> productsInfo = new List<ProductInfo>();
using (var channel = GetClientChannel<IService>("http://localhost:51383/Service/Service.svc"))
{
Parallel.ForEach(products, product =>
{
Request myRequest = new Request();
Response myResponse = null;
try
{
myRequest.ID = product;
myResponse = channel.GetProductInfo(myRequest);
productsInfo.Add(myResponse.Info);
}
catch (Exception ex)
{
// Continue build ProductInfo list
}
});
}
DoSomething(productsInfo);
What's the best approach for something like this?
Would the parallel for each improve the performance or it will not be affected since i'm calling the service in the same host/port?

If you service is not concurrent, I think doing the parallel for each will not make much difference since calls to the service will only be handled one at a time. What you need to do is either make your service Concurrent by using something like:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
class MyService : IMyService
or change the InstanceContext mode in the service behavior so that each call to the service creates a new process on the server where the service is hosted, something like
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
class MyService : IMyService
If you do any of these, make sure you take care of issues related to threading. More about these attributes is explained in WCF Concurrency tutorial

Related

Unable to return a value from SignalR Client from a different method

I'm working on a Winforms app that executes SQL Procedures through a SignalR client. I'm relatively new to using SignalR and am still wrapping my head around it.
I start off by running my connection method to establish a connection with my SignalR service. I have two addresses configured ready for when I puslish but the DEV configuration leads to the SignalR service I am hosting locally.
Connection to SignalR (ConnectHub)
private async Task ConnectHub()
{
string hubAddress = "";
#if DEBUG
HubAddress = ConfigurationManager.AppSettings["HubAddress_DEV"];
#else
HubAddress = ConfigurationManager.AppSettings["HubAddress_PROD"];
#endif
if (string.IsNullOrEmpty(hubAddress))
{
MessageBox.Show("Hub Address is missing from configuration.");
}
ConnectionHandler.Client = new HubClient(hubAddress, "MyHub");
ConnectionHandler.Client.MyAlert += ConnectionHandler.ClientOnMyAlert;
ConnectionHandler.Client.ServerErrorEvent += ConnectionHandler.ClientOnServerErrorEvent;
await ConnectionHandler.Client.Connect(new List<string>() {
VehicleInfo.ThisVehicle.WarehouseCode,
VehicleInfo.ThisVehicle.VehicleName
});
}
My client is stored globally in my ConnectionHandler class where my event handlers are also kept. (I have breakpoints on these as I have not implemented them yet)
ConnectionHandler Class
public static class ConnectionHandler
{
public static HubClient Client { get; set; }
public static void ClientOnServerErrorEvent(string error)
{
throw new NotImplementedException(); //Currently not implemented
}
public static async Task ClientOnMyAlert(EnumMyAlertType alerttype, string message, Exception exception)
{
await Task.Yield(); //Currently not implemented
}
}
When I call the code to Invoke the procedure in my SignalR client, it returns a DataTable to me which is the intended result.
Call to SignalR
await ConnectHub();
DataTable dt = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>(
"FetchStatuses",
new object[0]); //This call works as intended and returns a populated DataTable
StatusInfo = new CStatuses();
All the above code is currently done on the main form, however I wanted to move this call to SignalR into a constructor to try and tidy things up.
The problem comes when I try to move this call into another method, the program hangs as I don't think it has received the return value from SignalR, I have placed a breakpoint beneath it and it is not reached. A TryCatch reveals nothing as it hangs within the "Try" with no exception.
Calling from contructor
public CStatuses()
{
Statuses = new List<CStatus>();
var dataTable = ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0])
.Result; //My program hangs on this line and proceeds no further
I am at a loss as to why it is doing this when I can get a value from the client from the form and when other members of my team have tried to do the same thing they can make a call to SignalR also from a different method.
Does anyone have any ideas as to how I can make this work?
I realize this has gotten quite long but if I can elaborate on things please let me know
FIXED CODE THANKS TO SOLUTION:
I have moved the code from my CStatuses constructor into a new async method within the same class and called it after initialization. This removes the need for .Result and appears to solve the problem for me.
public async Task PopulateStatuses()
{
var dataTable = await ConnectionHandler.Client.Connection.InvokeCoreAsync<DataTable>("FetchStatuses",
new object[0]);
Statuses = new List<CStatus>();
foreach (DataRow row in dataTable.Rows)
{
var status = new CStatus
{
StatusId = Common.Utility.GetInt16Value(row["StatusID"]),
StatusCode = Common.Utility.GetStringValue(row["StatusCode"]),
Description = Common.Utility.GetStringValue(row["Description"])
};
Statuses.Add(status);
}
}
You are running into a deadlock with the .Result call, I would suggest creating an async method in the CStatuses class and after you initialize your CStatuses class call the websocket for data.

Castle Windsor WCF Facility is not processing one way operations

I currently have a simple use case.
1) A client app that connects to a WCF Service using Castle's AsWcfClient option.
2) WCF Service "A" that is hosted using Castle and is injecting a single dependency. This dependency is a client proxy to another WCF Service (Call it Service "B").
3) Service "B" does some work.
To visualize: Client -> Service "A" with Castle injected proxy to -> Service "B"
Simple right? Works without issue IF, and that's a big if, the Service "B" host is up and running.
The behavior I have seen and can reproduce on demand is that if Service "B" is down, the call chain completes without any hint that there is any issue. To say it another way, there is no resolution exception thrown by Castle nor any WCF exception. I have isolated this to how IsOneWay=true operations are handled.
This is a major issue because you think that everything has executed correctly but in reality none of your code has been executed!
Is this expected behavior? Is there away I can turn on some option in Castle so that it will throw and exception when a WCF Client proxy is the resolved dependency? Some other option?
One more note, the only clue that you have that is issue is occurring is when/if you do a Container.Release() on the client proxy as it throws an exception. This can't be depended upon thou for various reasons not worth getting into here.
Thank!
Additionally below is the code that recreates this issue. To run it
1) Create a new Unit Test project in Visual Studio
2) Add the Castle Windsor WCF Integration Facility via NuGet
3) Paste the code from below into a .cs file, everything is in one to make it easy.
4) Run the two unit tests, SomeOperation_With3Containers_NoException() works as the dependency service (Service "B" from above) is running. SomeOperation_With2Containers_NoException() fails are the .Release
5) Set break points and you can see that no code is hit in the implementations.
****UPDATE****: The primary way this needs to be handled is with an IErrorHandler implantation (As mentioned by Roman in the comments below). Details and an example can be found here: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.110).aspx
Use this implementation to log any exception on the One Way operation and use that data to take the appropriate action.
using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace UnitTestProject1
{
[ServiceContract]
public interface IServiceContractA
{
[OperationContract(IsOneWay = true)]
void SomeOperation();
}
[ServiceContract]
public interface IServiceDependancy
{
[OperationContract]
void SomeOperation();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceContractAImplementation : IServiceContractA
{
private IServiceDependancy ServiceProxy;
public ServiceContractAImplementation() { }
public ServiceContractAImplementation(IServiceDependancy dep)
{
ServiceProxy = dep;
}
public void SomeOperation()
{
ServiceProxy.SomeOperation();
}
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceDependancyImplementation : IServiceDependancy
{
public void SomeOperation()
{
//do nothing, just want to see if we can create an instance and hit the operation.
//if we need to do something, do something you can see like: System.IO.File.Create(#"d:\temp\" + Guid.NewGuid().ToString());
}
}
public class ServiceCastleInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
var returnFaults = new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true, HttpHelpPageEnabled = true };
container.Register(Component.For<IServiceBehavior>().Instance(returnFaults));
//local in-proc service hosting
var namedPipeBinding = new NetNamedPipeBinding();
//it works using Named Pipes
var serviceModelPipes = new DefaultServiceModel().AddEndpoints(
WcfEndpoint.BoundTo(namedPipeBinding).At("net.pipe://localhost/IServiceContractA")
).Discoverable();
container.Register(Component.For<IServiceContractA>()
.ImplementedBy<ServiceContractAImplementation>()
.LifeStyle.PerWcfOperation()
.AsWcfService(serviceModelPipes)
);
//our service (IServiceContractA) has a dependancy on another service so needs a client to access it.
container.Register(Castle.MicroKernel.Registration.Component.For<IServiceDependancy>()
.AsWcfClient(WcfEndpoint.BoundTo(namedPipeBinding)
.At(#"net.pipe://localhost/IServiceDependancy")).LifeStyle.Transient);
}
}
public class ServiceDependancyCastleInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
var returnFaults = new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true, HttpHelpPageEnabled = true };
container.Register(Component.For<IServiceBehavior>().Instance(returnFaults));
//local in-proc service hosting
var namedPipeBinding = new NetNamedPipeBinding();
var serviceModel = new DefaultServiceModel().AddEndpoints(
WcfEndpoint.BoundTo(namedPipeBinding).At("net.pipe://localhost/IServiceDependancy")
).Discoverable();
container.Register(Component.For<IServiceDependancy>()
.ImplementedBy<ServiceDependancyImplementation>()
.LifeStyle.PerWcfOperation()
.AsWcfService(serviceModel)
);
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void SomeOperation_With3Containers_NoException()
{
//setup the container that is going to host the service dependancy
using (var dependancyContainer = new WindsorContainer().Install(new ServiceDependancyCastleInstaller()))
{
//container that host the service that the client will call.
using (var serviceContainer = new WindsorContainer().Install(new ServiceCastleInstaller()))
{
//client container, nice and simple so doing it in the test here.
using (var clientContainer = new WindsorContainer())
{
clientContainer.AddFacility<WcfFacility>();
var endpoint = WcfEndpoint.BoundTo(new NetNamedPipeBinding())
.At("net.pipe://localhost/IServiceContractA");
clientContainer.Register(Castle.MicroKernel.Registration.Component.For<IServiceContractA>()
.AsWcfClient(endpoint).LifeStyle.Transient);
var proxy = clientContainer.Resolve<IServiceContractA>();
proxy.SomeOperation();
clientContainer.Release(proxy);
}
}
}
}
[TestMethod]
public void SomeOperation_With2Containers_NoException()
{
//this one fails.
// this test omits the dependancy that the IServiceContractA has
//Note that all seems to work, the only hint you have that it doesnt
//is the .Release call throws and exception.
//container that host the service that the client will call.
using (var serviceContainer = new WindsorContainer().Install(new ServiceCastleInstaller()))
{
//client container, nice and simple so doing it in the test here.
using (var clientContainer = new WindsorContainer())
{
clientContainer.AddFacility<WcfFacility>();
var endpoint = WcfEndpoint.BoundTo(new NetNamedPipeBinding())
.At("net.pipe://localhost/IServiceContractA");
clientContainer.Register(Castle.MicroKernel.Registration.Component.For<IServiceContractA>()
.AsWcfClient(endpoint).LifeStyle.Transient);
var proxy = clientContainer.Resolve<IServiceContractA>();
//this call seems like it works but any break points
//in code don't get hit.
proxy.SomeOperation();
//this throws and exception
clientContainer.Release(proxy);
}
}
}
}
}
One way operations exists for the purpose of "Fire and forget" scenarios. You don't care about result, whether it was successful or not. You don't have to wait for the server to respond (only the initial TCP handshake if it's HTTP binding). By using one way operations, the client only gets the confidence that the server received the message successfully on the wire, and the server makes no guarantees that it will succeed in processing the message. This is true in HTTP protocol. In other protocols, like Microsoft MSMQ, or IBM MQ, the server doesn't even need to be online at the same time as the client.
In your scenario, The client does not receive an exception, because service A is up and running. If service A was down, you would have seen an error (Again, assuming HTTP, or in your case .net pipe). The condition of service B does not matter, because service B is an implementation detail of service A, and your client doesn't care about service A return values. If your were to debug service A (by attaching to it) while service B is down, you would have seen first chance, and maybe even unhandled exceptions (depending on the implementation of service A).
Castle should not have thrown an exception anyway, because it has successfully resolved a proxy for service B in service A. The fact that service B is down is no concern of Castle, or any other DI container for that matter.

How to call a WCF method asynchronously from MVC4 WebAPI

I am new to the WebApi, .Net world and am totally confused with all the information available as to what approach I should take. I have created a WebService using MVC4 WebApi that Twilio calls when a text message is received. I need to respond to this text message. I am consuming a WCF method which is currently being called synchronously. Since it is possible that my process can take longer than 3-5 seconds to process a reply to the text message the connection to Twilio gets disconnected due to timeout. So I am looking for ways to call this WCF method asynchronously.
My question is to call the WCF method (I am calling the WCF using a Object Factory and using)
do I need to update the contract to say Async? I am little confused on that.
BTW my Web Service is in IIS7 and am using .Net4.5 framework and MVC4 WebApi .
My code is somewhat like this: So I would like to call the SendSms part asynchronously. How do I do that? Can I simply use Task.Run Async and Await?
using Twilio.Mvc;
using Twilio.TwiML.Mvc;
using Twilio.TwiML;
public class SmsController : ApiController
{
[HttpPost]
public HttpResponseMessage Post([FromBody]SmsRequest smsReq)
{
var response = new Twilio.TwiML.TwilioResponse();
//validation checks..
try
{
-- call to WCF to get the List of sms to be sent
if ((txtMessageResponse != null) && (txtMessageResponse.SmsMessageInfo.Count > 0))
{
_smsStagingList = txtMessageResponse.SmsMessageInfo;
foreach (TextMessageStaging prepareTextMessageResponse in _smsStagingList)
{
smsDTO textMessageItems = new smsDTO();
textMessageItems.PhoneNumber = prepareTextMessageResponse.PhoneNumber;
textMessageItems.SmsMessage = prepareTextMessageResponse.SmsMessageBody;
isTxtMessageSent = SendSms(textMessageItems);
//If the messages were sent then no need to set the flag to be updated
if (isTxtMessageSent)
{
txtMessageStatusToBeUpdated = false;
}
}
return Request.CreateResponse(HttpStatusCode.OK, twilioResponse.Element);
}
else
{
//send error response
}
catch (Exception msgProcessingError)
{
//send error response again as processing error
}
finally
{
//set the outbound flag in the table
}
}
private bool SendSms(smsDTO textMessageItems)
{
bool isTxtMessageSent = false;
PushMessageRequest txtMessageRequest = new PushMessageRequest();
PushMessageResponse txtMessageResponse = null;
txtMessageRequest.SmsMessageInfo = new SendTextMessage(); //instantiate the dto
txtMessageRequest.SmsMessageInfo.ToPhone = textMessageItems.PhoneNumber;
txtMessageRequest.SmsMessageInfo.TextMessage = textMessageItems.SmsMessage;
try
{
using (ITextService textService = ObjectFactory.SendSmsMessage())
{
txtMessageResponse = textService.SendSmsMessage(txtMessageRequest);
}
isTxtMessageSent = txtMessageResponse.IsSuccessful;
}
catch (Exception ex)
{
isTxtMessageSent = false;
}
return isTxtMessageSent;
}
Twilio evangelist here.
OK, so you have a Web API method in which you call a WCF method that is potentially long running. There are two problems to solve here:
How do you call the WCF method in a way that does not block the Web API method from returning a response
How do you get Twilio to wait until the WCF method has finished
I wrote a blog post a while ago that shows you how to create an indefinite wait loop in an IVR by leveraging .NET's Task Parallel library and the loop attribute on Twilios <Play> verb.
The gist of the post is that you can use the TPL's StartNew method to start the long running WCF method on a new thread. This lets ASP.NET continue and lets you return some TwiML so Twilio does not end the call. Then you pair that with a continuation which lets you know when the WCF service request is done and you can signal back to Twilio using the REST API to redirect the in-progress call to a new set of TwiML instructions.
Hope that helps.

Calling multiple WCF services return error - Disposed Object can't be used

My WCF service provides multiple services from different end points.
Currently my client app calls these methods independently as shown below:
object result1 = null;
object result2 = null;
using (OperationContextScope contextScope = new OperationContextScope((IContextChannel)ServiceInstance))
{
MyService.AddHeaders();
result1 = ServiceInstance.Method1()
}
//some other processing depending on the value of result1
using (OperationContextScope contextScope = new OperationContextScope((IContextChannel)ServiceInstance))
{
MyService.AddHeaders();
result2 = ServiceInstance.Method2()
}
Now, to improve performance, I tried doing the following:
using (OperationContextScope contextScope = new OperationContextScope((IContextChannel)ServiceInstance))
{
MyService.AddHeaders();
result1 = ServiceInstance.Method1()
result2 = ServiceInstance.Method2()
}
//some other processing depending on the value of result1 && result2
But this is failing with the error: "disposed object can't be used" and in the inner exception the disposed object is ChannelService.
Can someone help me how can I combine multiple WCF service calls under one OperationContextScope?
Thanks
Aravind
I am not certain but this may be because your service might be single call (and/or does not support sessions). You may want to tweak with service behaviors to get this working.
If the intention is only to make more than 1 call within the single OperationContextScope, you may use Innerchannel of the service.
using (OperationContextScope contextScope = new
OperationContextScope((IContextChannel)abc.InnerChannel))
{
/* Add Headers */
MessageHeader header
= MessageHeader.CreateHeader(
"Service-Bound-CustomHeader",
"http://Microsoft.WCF.Documentation",
"Custom Happy Value."
);
header = MessageHeader.CreateHeader(
"Service-Bound-OneWayHeader",
"http://Microsoft.WCF.Documentation",
"Different Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
Console.WriteLine(abc.GetData(100));
Console.WriteLine(abc.GetDataUsingDataContract(new ServiceReference1.CompositeType()).ToString());
}

Is this a correct way to host a WCF service?

For some testing code, I'd like to be able to host a WCF service in only a few lines. I figured I'd write a simple hosting class:
public class WcfHost<Implementation, Contract> : IDisposable
where Implementation : class
where Contract : class
{
public readonly string Address = "net.tcp://localhost:8000/";
private ServiceHost _Host;
public WcfHost ()
{
_Host = new ServiceHost (typeof (Implementation));
var binding = new NetTcpBinding ();
var address = new Uri (Address);
_Host.AddServiceEndpoint (
typeof (Contract),
binding,
address);
_Host.Open ();
}
public void Dispose ()
{
((IDisposable) _Host).Dispose ();
}
}
That can be used like this:
using (var host = new WcfHost<ImplementationClass, ContractClass> ()) {
Is there anything wrong with this approach? Is there a flaw in the code (esp. about the disposing)?
The Dispose method of the host can throw an exception if the host is in "faulted" state. If this happens you will not see what actually went wrong as the original exception is lost. For test code this might not be an issue but it still can be in your way if you try to figure out why something does not work.
I did not test it but the following should be OK in your Dispose method:
if (_Host.State == CommunicationState.Faulted)
{
_Host.Abort();
}
else
{
_Host.Close();
}
This seems fine to me if you are OK with the limitations of a fixed binding and server address .
You must be sure that the code within the using lasts as long as you want the host to be available.
If I would implement that Self Host, I would put it in a Windows Service, using the events OnStart and OnStop. Also, do the following changes for best practices:
Put the endpoint config in a App.Config file - better to manage in a production enviroment.
Separate the Host Service from the implementation and contract binaries.
You can also look at MSDN:
http://msdn.microsoft.com/en-us/library/ms730158%28v=VS.90%29.aspx
There's a good how to "Host the service in a Windows Service"

Categories

Resources