Exception in multi-Task WCF channel usage (ems) - c#

I receive an exception of type
Exception receiving EMS message: The service did not respond.
When calling the code below from more than one task.
Task.Factory.StartNew(() =>
{
var service = CreateChannel();
try
{
return service.GetStuff(string blah);
}
finally
{
var channel = ((IClientChannel)service);
try
{
channel.Close();
}
catch
{
channel.Abort();
}
}
});
private IService CreateChannel()
{
lock (_channelFactory)
{
return _channelFactory.CreateChannel();
}
}
If i remove the Channel.Close() there is no exception.
Any ideas?

Self Answer
Updating my tibco.ems.wcf assembly fixed this.

Related

ASP.NET legacy app using MassTransit fails to send message on second try

I have an ASP.NET 4.7.2 app and I'm not able to migrate to new .NET version yet.
Right now we are using Masstransit 6.3.2.
What happens is that we create a bus like this in my Global.asax.cs:
busControl = Bus.Factory.CreateUsingRabbitMq((cfg) =>
{
cfg.Host(_settings.Host, _settings.VirtualHost, hfg =>
{
hfg.Password(_settings.Password);
hfg.Username(_settings.UserName);
});
});
container.RegisterInstance<IBusControl>(busControl);
container.RegisterInstance<IBus>(busControl);
Bus is passed to the container (IUnityContainer) and injected into a controller:
[RoutePrefix("api/Message")]
public class MessageController : ApiController
{
private readonly IBus bus;
public MessageController(IBus bus)
{
this.bus = bus;
}
[HttpPost()]
[ResponseType(typeof(void))]
[Route(nameof(SendTestMessage))]
public async Task<IHttpActionResult> SendTestMessage(TestMessage message)
{
if (message == null)
return BadRequest();
try
{
var endpoint = await bus.GetSendEndpoint(new Uri("exchange:testQueue"));
await endpoint.Send(message);
return Ok();
}
catch (Exception ex)
{
Logger.Fatal(ex, "HttpRequest {requestname} failed", nameof(SendTestMessage));
return StatusCode(HttpStatusCode.InternalServerError);
}
}
}
First time the action is called, everything is fine and message is passed to the RabbitMq queue. On the second attempt, it fails with an exception.
There is no stacktrace to the exception. Source of the exception is System.Web.
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object
This exception was originally thrown at this call stack:
System.Web.ThreadContext.AssociateWithCurrentThread(bool)
So fix was quite easy.
I just changed
var endpoint = await bus.GetSendEndpoint(new Uri("exchange:testQueue"));
To
var endpoint = await bus.GetSendEndpoint(new Uri("exchange:testQueue")).ConfigureAwait(false);

Propagate exception message from service to controller .NET

I have a .NET appplication where there is a controller for receiving user requests, a service Service 1 which calls another service Service 2.
I have some code in the Service 2 where I query the database(DynamoDB) and get a 500 error in response when the user request values are incorrect. I want to handle this such that I catch this error/exception and send back the error message along with a 400 status code from the controller to the user. How should I modify the code to do this?
This is what I have tried. Currently, I'm just printing the error in Service 1 but I need to send it to the controller. Is sending the error message to the controller by throwing exceptions along the way the right way to do it?
The below code is similar to the actual code
Controller:
[HttpGet]
[Authorize(Policy = "Read-Entity")]
[Route("byParams/{param1}/{param2}")]
[Produces(typeof(DynamoResult<EntityResponse>))]
public async Task<IActionResult> ListByParams([FromQuery] DynamoQuery entityQuery)
{
try
{
return await HandleRequest(async () =>
{
return Ok((await _entityStore.ListByParams(entityQuery)));
});
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
Service 1:
public async Task<DynamoResult<EntityResponse>> ListByParams(DynamoQuery entityQuery)
{
results = new DynamoResult<Entity>();
try {
results = await GetPagedQueryResults(entityQuery);
}
catch (Exception e) {
Console.WriteLine(e);
}
return new DynamoResult<EntityResponse>
{
Data = results.Data.Select(_mapper.Map<EntityResponse>).ToList(),
};
}
Service 2:
private async Task<DynamoResult<TResponse>> GetPagedQueryResults(DynamoQuery query)
{
var results = new List<Document>();
try{
results = await search.GetNextSetAsync();
}
catch(Exception e){
throw new PaginationTokenException(e.Message);
}
return results;
}
[Serializable]
public class PaginationTokenException : Exception
{
public PaginationTokenException() { }
public PaginationTokenException(string message)
: base(message) {
throw new Exception(message);
}
public PaginationTokenException(string message, Exception inner)
: base(message, inner) { }
}
Assuming you want to hide implementation details from the controller (i.e. you don't want the controller to know/care that it's DynamoDB), I would create a custom exception and throw that from Service1.
Service1 would look something like this:
public async Task<DynamoResult<EntityResponse>> ListByParams(DynamoQuery entityQuery)
{
results = new DynamoResult<Entity>();
try {
results = await GetPagedQueryResults(entityQuery);
}
catch (Exception e) {
throw new MyCustomException('My error message', e);
}
return new DynamoResult<EntityResponse>
{
Data = results.Data.Select(_mapper.Map<EntityResponse>).ToList(),
};
}
In the controller you can then capture that exception explicitly:
[HttpGet]
[Authorize(Policy = "Read-Entity")]
[Route("byParams/{param1}/{param2}")]
[Produces(typeof(DynamoResult<EntityResponse>))]
public async Task<IActionResult> ListByParams([FromQuery] DynamoQuery entityQuery)
{
try
{
return await HandleRequest(async () =>
{
return Ok((await _entityStore.ListByParams(entityQuery)));
});
}
catch (MyCustomException e)
{
return BadRequest(e.Message);
}
}

Exceptions in WCF services

I have the following code in my ServiceBase abstract class:
internal ServiceResponse ExecuteNonQuery(Action action)
{
try
{
action();
return new ServiceResponse() { IsFaulty = false };
}
catch (DbEntityValidationException e)
{
OnDbEntityValidationException(e);
return new ServiceResponse() { IsFaulty = true, Exception = e};
}
catch (Exception e)
{
_logger.Log(e);
return new ServiceResponse() {IsFaulty = true, Exception = e};
}
}
All my services derives from this class and my WCF service endpoint looks like this:
public ServiceResponse Add(Client client)
{
_logger.LogInformation($"ClientService.Add()");
return ExecuteNonQuery(() =>
{
using (var context = _contextFactory.Build())
{
context.Clients.Add(_serviceToDalMapper.Map(client));
context.SaveChanges();
}
});
}
On the client side I have similar Try/Catch method when calling my service.
What I don't understand is that when an exception is thrown on the service side, the exception is catch, but I still get an System.ServiceModel.CommunicationException on the client side. Why ? I catched my exception, shouldn't my service just return the ServiceResponse?
Add a try-catch inside your current catch, looks like the call is generating an exception, possibly generated inside the catch.
catch (DbEntityValidationException e)
{
try
{
OnDbEntityValidationException(e);
return new ServiceResponse() { IsFaulty = true, Excepetion = e};
}
catch
{
return new ServiceResponse() { IsFaulty = true, Excepetion = new Exception("Error handling the error")};
}
}
WCF can't serialize the Exception object (which makes sense in a way).
So an exception was thrown in my catch block, that's the fault here.
According to WCF best practices, I should be using FaultContract to communicate exception to the client.

Handling exception in task

I'm new to TPL.
I need to handle exception when the SendEmailAlert() method throws any error.Is the following code correct please?
public Task MyMethod()
{
DoSomething();
try
{
string emailBody = "TestBody";
string emailSubject = "TestSubject";
Task.Run(()=> SendEmailAlert(arrEmailInfo));
}
catch (AggregateException ex)
{
ex.Handle((e) =>
{
log.Error("Error occured while sending email...", e);
return true;
}
);
}
}
private void SendEmailAlert(string[] arrEmailInfo)
{
MyClassX.SendAlert(arrEmailnfo[0], arrEmailnfo[1]);
}
I forced an error from within SendEmailAlert() method.But the exception is not getting caught. Could someone advise?
Thanks.
Your Task.Run runs in a different context (you would need a try/catch inside it; or check if the task is done). You could change to use async/await.
Example:
public async void MyMethod()
{
try
{
await ExceptionMethod();
}
catch (Exception ex)
{
// got it
}
}
public async Task ExceptionMethod()
{
throw new Exception();
}

Reusing try catch for wcf call

I have a series of methods that call wcf services and all of them have the same try catch code
Response Method1(Request request)
{
Response response = null;
using(ChannelFactory<IService1> factory = new ChannelFactory<IService1>(myEndpoint))
{
IService1 channel = factory.CreateChannel();
try
{
response = channel.Operation(request);
}
catch(CommunicationException ex)
{
// Handle Exception
}
catch(TimeoutException ex)
{
// Handle Exception
}
catch(Exception ex)
{
// Handle Exception
}
}
return response;
}
And so on (I have 6 methods like this for different services).. how can i encapsulate all the service calls and handle the exceptions in a single method
EDIT
Following Nathan A's advice I created a simple generic method:
protected TResult ExecuteAndCatch<TResult>(Func<T, TResult> serviceCall, T request)
where T : Request
where TResult : Response
{
try
{
return serviceCall(request);
}
catch (CommunicationException ex)
{
}
catch (TimeoutException ex)
{
}
catch (Exception ex)
{
}
return null;
}
The new methods would like this
Response NewMethod1(Request request)
{
Response response = null;
using(ChannelFactory<IService1> factory = new ChannelFactory<IService1>(myEndpoint))
{
IService1 channel = factory.CreateChannel();
response = channel.Operation(request);
}
return response;
}
and i'm trying to call it like
Response response = ExecuteAndCatch<Response>(NewMethod1, new Request())
What am I doing wrong?
Use a wrapper function.
Take a look at this article: http://mytenpennies.wikidot.com/blog:writing-wcf-wrapper-and-catching-common-exceptions
Here's an example from the article:
private void ExecuteAndCatch<T> (Action<T> action, T t) {
try {
action (t);
Success = true;
}
catch (TimeoutException) {
Success = false;
Message = "Timeout exception raised.";
}
catch (CommunicationException) {
Success = false;
Message = "Communication exception raised.";
}
}
If your client derives from ClientBase<T> e.g MyClient : ClientBase<IWCFService>
You could then create your own base class that provides methods that will wrap the common functionality.
The below sample code could be expanded to allow the final derived class to specify what to do when a particular method call fails. Here I just call HandleError
In specific client class
//method that returns a value
public int Ping()
{
return Protect(c => c.Ping());
}
//void method usage
public void Nothing(int stuff)
{
Protect(c => c.Nothing(stuff));
}
In client base class
protected void Protect(Action<IWCFService> action)
{
Protect(c => { action(c); return true; });
}
//add other exception handling
protected Protect<T>(Func<IWCFService, T> func)
{
try
{
return func(Channel);
}
catch (FaultException e)
{
HandleError(e);//up to you to implement this and any others
}
return default(T);
}
inject the various clients through an interface and then run the operation in a single place?
HttpResponse performOperation(IServiceClient injectedServiceClient)
{
IServiceClient client = injectedServiceClient;
try
{
client.Operation();
}
catch(CommunicationException ex)
{
// Handle Exception
}
catch(TimeoutException ex)
{
// Handle Exception
}
catch(Exception ex)
{
// Handle Exception
}
return httpResponse(httpStatusCode.OK);
}

Categories