I have a WCF service, that needs to convert a video. I need to call that method from my Xamarin app. If I call the regular method everything works as expected, but if I call the Async method, I get the error below.
I already set the IncludeExceptionDetailInFaults on my WCF service to true, to get the details of the error.
WCF:
The interface:
[ServiceContract]
public interface IConvert
{
[OperationContract]
bool ConvertVideo(string path);
}
The service:
public class ConvertService : IConvert
{
public bool ConvertVideo(string path)
{
Console.WriteLine("Converting video... wait 3 sec");
Thread.Sleep(3000);
Console.WriteLine("Video converted!");
Console.WriteLine(path);
return true;
}
}
Xamarin:
This works:
try
{
_Client.ConvertVideo(GetFullFtpPath());
}
catch (Exception e) { }
This throws an error:
try
{
_Client.ConvertVideoAsync(GetFullFtpPath());
}
catch (Exception e) { }
The error:
{System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]:
Error in deserializing body of request message for operation 'ConvertVideo'.
OperationFormatter encountered an invalid Message body.
Expected to find node type 'Element' with name 'ConvertVideo' and namespace 'http://tempuri.org/'.
Found node type 'Element' with name 'ConvertVideoAsync' and namespace 'http://tempuri.org/'
(Fault Detail is equal to Error in deserializing body of request message for operation 'ConvertVideo'.
OperationFormatter encountered an invalid Message body.
Expected to find node type 'Element' with name 'ConvertVideo' and namespace 'http://tempuri.org/'.
Found node type 'Element' with name 'ConvertVideoAsync' and namespace 'http://tempuri.org/').}
EDIT: This only happens on Xamarin. I have tried it with WPF and everything works fine there.
your _Client should have _Client.ConvertVideoCompleted. your code should be something like
try
{
_Client.ConvertVideoCompleted+= yourHandler;
_Client.ConvertVideo(GetFullFtpPath());
}
catch (Exception e) { }
refer to https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-call-wcf-service-operations-asynchronously
Related
My code:
public class MyWebService : IDisposable
{
private readonly NancyHost _host;
public MyWebService(int port = 7017)
{
var uri = new Uri(string.Format("http://localhost:{0}", port));
_host = new NancyHost(uri);
_host.Start();
}
public void Dispose()
{
if (_host != null)
{
_host.Stop();
_host.Dispose();
}
}
}
internal class MyWebModule : NancyModule
{
public MyWebModule()
{
Get["/"] = _ => "Received GET request";
}
}
When running following HTTP request: GET http://localhost:7017/ using Insomnia REST client, I'm getting following cryptic exceptions:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Cannot convert type 'Nancy.ErrorHandling.DefaultStatusCodeHandler.DefaultStatusCodeHandlerResult' to 'Nancy.Response''
at CallSite.Target(Closure , CallSite , Object )
With Source: Anonymously Hosted DynamicMethods Assembly
followed up by
Nancy.ViewEngines.ViewNotFoundException
at Nancy.ViewEngines.DefaultViewFactory.GetRenderedView(String viewName, Object model, ViewLocationContext viewLocationContext)
without any additional infromation on exception.
The REST client then shows error 404.
What have I defined wrong? I've followed the following example: building-a-simple-http-server-with-nancy
If you run your code under debugger - ensure that thrown exception is actually unhandled. Code might throw exceptions and your debugger (if configured to do so) might break on them, even if those exceptions are handled (by some catch block). Since you receive 404 reply after all and not crash - I guess those exceptions are part of "normal" nancy flow and so are handled.
As for 404 - your module is internal and Nancy will not discover it. Make it public instead:
public class MyWebModule : NancyModule
{
public MyWebModule()
{
Get["/"] = _ => "Received GET request";
}
}
Is it possible, in Web API 2 to directly return the Exception message in the response's Status ?
For example, if I was writing a WCF Service (rather than Webi API), I could follow this tutorial to directly return an Exception message as part of the response status:
Here, the web service doesn't return any data in the Response, and the error message gets returned directly in the Status Description.
This is exactly what I'd like my Web API services to do when an exception occurs, but I can't work out how to do it.
Most suggestions suggest using code like below, but then the error message will then always get returned in a separate response string, rather than being part of the Status.
For example, if I were to use this code:
public IHttpActionResult GetAllProducts()
{
try
{
// Let's get our service to throw an Exception
throw new Exception("Something went wrong");
return Ok(products);
}
catch (Exception ex)
{
return new System.Web.Http.Results.ResponseMessageResult(
Request.CreateErrorResponse((HttpStatusCode)500,
new HttpError("Something went wrong")));
}
}
... then it returns a generic 500 message, and the exception is returned in a JSON string.
Does anyone know how to modify a Web API function (which returns an IHttpActionResult object) to do this ?
You could register a custom global filter that will handle all Exceptions. Something like:
public class CatchAllExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
}
}
You will need to register it in WebApiConfig.cs, with:
config.Filters.Add(new CatchAllExceptionFilterAttribute());
This filter will be hit everytime there is an unhandled exception in the system and set the http response to the exception message. You could also check the different types of exception and alter your response accordingly, for example:
public override void OnException(HttpActionExecutedContext context)
{
if(context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented)
{
Content = new StringContent("Method not implemented.")
};
}
else
{
context.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message)
};
}
}
https://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling
Please refer above link, it will help you!
I have the following exception filter:
public class ArgumentExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
var exception = actionExecutedContext.Exception as ArgumentException;
if (exception != null)
actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.BadRequest, new
{
FailureReason = exception.Message
});
base.OnException(actionExecutedContext);
}
}
I then call the following action with a null 'id':
public object Get(string id)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException(nameof(id));
return Client.getProfileForUser(ExternalAuthToken, id);
}
I set a break point in the ExceptionFilter and while stepping through the code I can confirm it does set the Response correctly.
My logging action filter shows the response has been set correctly but the browser receives a Server 500 error with full exception details in HTML format.
I've tried:
Setting customErrors to 'Off' and this had no effect.
I've added Message Handler and checked that the response is correct at the Message Handler level. It is correct at this level.
Why is the response set in the filter being overridden, and by where in the pipeline would this be happening?
Edit (Now Resolved)
I have resolved this issue by deleting the "bin" folder and rebuilding. I am not sure how this could have fixed it however.
I use the SignalR 1.0.
When exception occurs on the server, the client gets a message like this
{"I":"0","E":"Exception of type 'System.Exception' was thrown.","T":" at METHODNAME in d:\PATH\TO\HUB.cs:line 227\r\n at METHODNAME in d:\PATH\TO\HUB.cs:line 51"}
But I want to make it more user-friendly. How to I can do it?
I have read a suggestion to put all server methods into try-catch block. But I think that it is not a true-way.
I traced the Exception and found that the Exception was catched in the Microsoft.AspNet.SignalR.Hubs.HubDispatcher.Incoming method. But it is internal static method which I cannot customize.
In the ideal case I want to get ability to convert an exception to a valid response.
You can use a HubPipelineModule.
For example:
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
public class MyHubPipelineModule : HubPipelineModule
{
protected override Func<IHubIncomingInvokerContext, Task<object>> BuildIncoming(Func<IHubIncomingInvokerContext, Task<object>> invoke)
{
return async context =>
{
try
{
// This is responsible for invoking every server-side Hub method in your SignalR app.
return await invoke(context);
}
catch (Exception e)
{
// If a Hub method throws, have it return the error message instead.
return e.Message;
}
};
}
}
Then in your Global.asax.cs:
protected void Application_Start()
{
GlobalHost.HubPipeline.AddModule(new MyHubPipelineModule());
//...
RouteTable.Routes.MapHubs();
}
after 2 days of trying to find out why my service isn't working I finally find the cause. Everytime I try to throw a new FaultException<AuthenticationException>, the server isn't actually throwing this but catching it itself.
So what is happening is that when I throw the exception the server is crashing with an unhandled System.ServiceModel.FaultException1`.
Here is my custom exception class:
[DataContract]
public class AuthenticationException
{
private string validationError;
[DataMember]
public string ValidationError
{
set { validationError = value; }
get { return validationError; }
}
public AuthenticationException()
{
}
public AuthenticationException(string valError)
{
validationError = valError;
}
}
And my interface:
[ServiceContract]
public interface IAuthenticator
{
[OperationContract]
[FaultContract(typeof(AuthenticationException))]
Account authenticateApplication(string userName, string Password);
What can cause this?
Edit: This is how I am throwing the exception:
catch (Exception)
{
throw new FaultException<AuthenticationException>(new AuthenticationException("There was a general error during the process."), new FaultReason("Error"));
}
Maybe your IIS server is not configured to allow passing exception to the client.
Follow the step 2 "Enable detailed errors for remote clients." of this post