Retrieve WCF Rest Response in Client - wcf

I'm using the WebChannelFactory<> to create a channel and interact with a WCF REST Service.
When there is an error, I want to retrieve the response from the channel to read the error message from the body of the response. But I cannot figure out how to get the response stream.
Here is my code:
using (var cf = new WebChannelFactory<T>(new Uri(url)))
{
var channel = cf.CreateChannel();
using (new OperationContextScope(channel as IContextChannel))
{
WebOperationContext.Current.OutgoingRequest.Headers
.Add("x-st-authtoken", HttpUtility.UrlDecode(Constants.General_AuthorizedToken));
WebOperationContext.Current.OutgoingRequest.Headers
.Add("x-st-tesskey", HttpUtility.UrlDecode(Constants.General_SessionKey));
try
{
a(channel);
}
catch (Exception ex)
{
throw new Exception("Status: " + ((int)WebOperationContext.Current.IncomingResponse.StatusCode).ToString());
}
}
}
In the catch statement, I want to include the data from the Response body...
It seems like an obvious thing, but I can't seem to find any information on the internet or anything.

Is there any specific reason for you to use ChannelFactory to interact with the REST service. I think it is easier to use HttpWebRequest object to invoke the REST service and there you can get the respone stream when an error is throw on the server.
Also check out RestSharp API through which you can achieve your task to read the response stream.

I believe it will throw a WebException.
so if you explicitly catch that type you can get use the WebException.Response property (which is an HttpWebReponse) on the exception and you can get the content from its stream.

Related

Get response and raw request when using proxies and resteasy client side framework 3.0.4

// Some setup steps
ResteasyProviderFactory factory = new ResteasyProviderFactory();
factory.registerProvider(com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider.class);
Client client = ClientBuilder.newClient(new ClientConfiguration(factory));
WebTarget target = client.target(webappURL.toURI() + "api/v1");
resteasyWebTarget = (ResteasyWebTarget) target;
// the real request
MyApiController myApiController = resteasyWebTarget.proxy(MyApiController.class);
ClientResponse response = (ClientResponse) myApiController.doSomeStuff();
The code above works great, but I want to really know what is going on in terms of real http request and real http response when
myApiController.doSomeStuff();
is executed.
I am wondering what the best way is to catch and log the "raw" request and a catch and log the "raw" http response. I am only interested in solutions for resteasy-client 3.0.2.Final or similar...
Thanks!
Not sure how to get it if everything went well (response code 200), but in case the server returned anything else, a sub type of ClientErrorException which gives you access to the response / status code / entity (message body) etc is thrown.
try {
myApiController.doSomeStuff();
} catch (BadRequestException ce) {
// Handle
} catch (ClientErrorException e) {
MyErrorObject obj = ce.getResponse().readEntity(MyErrorObject.class);
// Handle
}

In ASP.NET Web API, how can I make HTTP response syntax consistent if an exception is thrown?

I'm creating an HTTP API using ASP.NET Web API. I've noticed that if an exception occurs that I haven't handled, that behaviour is very different to if I deliberately throw an HttpResponseException. This will make it hard for clients to reliably handle an error and display the "reason" message.
Eg consider this code:
[HttpPost]
public void ThisWillThrowAnError()
{
try
{
var i = 0;
var b = 1 / i; // cause divide by zero exception for testing
}
catch (Exception ex)
{
HttpResponseMessage message = new HttpResponseMessage();
message.ReasonPhrase = "Error: " + ex.Message;
throw new HttpResponseException(message);
}
}
This creates a response which has the error in an HTTP header and the response code set to 500:
Error: This request could not be processed. Attempted to divide by zero.
The actual response body is empty.
However if I remove the try/catch block, or if an exception occurs for which I do not manually throw an HttpResponseException, I get totally different behaviour. Although the status code is still 500, the header message just says "Internal Server Error" and the message is encoded in a JSON format like this:
{
"Message": "An error has occurred.",
"ExceptionMessage": "Attempted to divide by zero.",
"ExceptionType": "System.DivideByZeroException",
"StackTrace": " at ProjectName.Controllers (etc....)"
}
I think I prefer the latter as it gives you more info for debugging but it removes the ability to customise the message or provide a user-readable message for the problem.
Why is WebAPI inconsistent with how it handles exceptions? Am I doing something myself to cause this inconsistency? It just seems rather messy and difficult to work with and may mean that the calling application will have to be coded to handle two different types of error response :(
When creating error responses, consider using HttpRequestMessage.CreateErrorResponse to create error responses that are consistent with the ones WebAPI sends.
This blog post should hopefully help:
http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
I would use message handlers. A message handler is a class that receives an HTTP request and returns an HTTP response. So you can basically change response structure in one place, and have same response for success and failure, and for all requests in your Web Api. You can read about it in my blog post: https://www.vladopandzic.com/asp-net-web-api/building-consistent-responses-asp-net-web-api/

Silverlight fault propagation and UserNamePasswordValidator

Scenario is a Silverlight client using Wcf service & custom authentication. To mitigate the 500/200 status code problem (avoid EndPointNotFound exception) I've applied the SilverLightFaultBehaviour. However, this does not work with UserNamePasswordValidator - When a FaultException is thrown from Validate(), it is not caught by the SilverLightFaultMessageInspector's implementation of BeforeSendReply.
So far, the only workaround I've found is using the alternative client stack instead ( WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);), but there are complications with using it which can no longer be ignored as a lot of our clients are on virtual machines, the silverlight client keeps crashing ( Silverlight 5 - Debugging npctrl.dll crash , http://communities.vmware.com/thread/394306?tstart=0 ).
My primary motivation is that I want to be able to distinguish a failed login from a connection error (the following code is from a client-side async callback method, and only works with the Client stack):
if (e.Error is MessageSecurityException)
{
this.HasLoginFailed.Value = Captions.Login_FailedLogin;
}
else
{
this.HasLoginFailed.Value = Captions.Login_FailedConnection;
}
Is there any other way of modifying the message sent when throwing a FaultException from UserNamePasswordValidator? Or any conceptually different way of doing custom authentication rather than what I am using which enables me to modify the message status or to keep it 200, or just to be able to distinguish a connection failure from bad credentials?
my server-side code for usernamepassword reg:
var serviceCredential = host.Description.Behaviors.Find<ServiceCredentials>();
serviceCredential.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
serviceCredential.UserNameAuthentication.CustomUserNamePasswordValidator =
new MyValidator();
When you throw a FaultException from MyValidator, it is wrapped as the InnerException of a MessageSecurityException, that's probably why you weren't able to catch it directly as a FaultException.
To add some information to the fault you are throwing, what you can do is adding a FaultCode:
throw new FaultException(
"Invalid user name or bad password.",
new FaultCode("BadUserNameOrPassword")
);
Then, catch the exception client-side and retrieve your FaultCode:
try { ... }
catch (MessageSecurityException e)
{
FaultException fault = (FaultException) e.InnerException;
String faultCode = fault.Code.Name;
// you can now display a meaningful error with the faultCode
}
I hope it will help!

how do i get an exception out of a web service?

I have a web service that runs perfectly when i reference it from within the project solution. As soon as i upload it to the remote server, it starts blowing up. Unfortunately, the only error message I get is on the client side "faultexception was unhandled by user code". Inside of the web service, I have exceptions handled in all of the methods, so I'm pretty sure it's getting caught somewhere, but I don't know how to see it. I suspect that the problem is permissions related, but I can't see where it's happening.
I tried placing an error message into object returns, but it's still not making it out; something like this:
public bool SetDirectReports(ADUser user)
{
try
{
var adEntry = new DirectoryEntry(string.Format("LDAP://<GUID={0}>", user.Guid), "administrator", "S3cur1ty");
if (adEntry.Properties["directReports"].Count > 0)
{
user.DirectReports = new List<ADUser>();
foreach (string directReport in adEntry.Properties["directReports"]) //is being returned as full distinguished name
{
var dr = new DirectoryEntry(string.Format("LDAP://{0}", directReport), "administrator", "S3cur1ty");
user.DirectReports.Add(GetUserByGuid(dr.NativeGuid));
}
return true;
}
else
{
user.DirectReports = new List<ADUser>();
return false;
}
}
catch (Exception ex)
{
user.HasError = true;
user.ErrorMessage = "Error setting direct reports: " + ex.Message;
return false;
}
}
but its' still not catching. I was hoping for a better approach. I'm not sure if I could add something that would output the exception to the console or what. Any help would be appreciated. TIA
P.S. this isn't necessarily the method thats crashing, there's a web of them in the service.
You should dump all of your exceptions to a log file on the server side; exposing error information to the client is a potential security risk, which is why it's turned off by default.
If you really want to send exception information to the client, you can turn it on. If you are using a WCF service you should set the "includeExceptionDetailsInFaults" property on for the service behavior, as described in this MSDN article on dealing with unhandled exceptions in WCF. Once you do so, you will have a property on the FaultException called Detail that should itself be a type of Exception.
For better error handling you should also take a look at typed faults using the FaultContract and FaultException<> class; these have the benefit that they don't throw the channel into a faulted state and can be handled correctly:
try
{
// do stuff here
}
catch (Exception ex)
{
var detail = new CustomFaultDetail
{
Message = "Error setting direct reports: " + ex.Message
};
throw new FaultException<CustomFaultDetail>(detail);
}
If you are using an ASP.NET Web Service, you should set the customErrors mode to "Off" in your web.config. This will send back the entire exception detail as HTML, which the client should receive as part of the SOAP exception that it receives.
The error your are seeing ("faultexception was unhandled by user code") is happening because this is a remote exception and it is standard behavior to only display exceptions on the local computer by default. In order to make it work how you intend, you need to change the customErrors section of the web.config and set it to Off
UPDATE: I found a related question: c# exception not captured correctly by jquery ajax
(Three years later..)
Here's the solution I came up with, along with some sample WCF code, and Angular code to catch, and display the exception message:
Catching exceptions from WPF web services
Basically, you just need to wrap your WCF service in a try..catch, and when something goes wrong, set a OutgoingWebResponseContext value.
For example, in this web service, I've slipped in an Exception, which will make my catch code set the OutgoingWebResponseContext value.
It looks odd... as I then return null, but this works fine.
public List<string> GetAllCustomerNames()
{
// Get a list of unique Customer names.
//
try
{
throw new Exception("Oh heck, something went wrong !");
NorthwindDataContext dc = new NorthwindDataContext();
var results = (from cust in dc.Customers select cust.CompanyName).Distinct().OrderBy(s => s).ToList();
return results;
}
catch (Exception ex)
{
OutgoingWebResponseContext response = WebOperationContext.Current.OutgoingResponse;
response.StatusCode = System.Net.HttpStatusCode.Forbidden;
response.StatusDescription = ex.Message.Replace("\r\n", "");
return null;
}
}
What is brilliant about this try..catch is that, with minimal changes to your code, it'll add the error text to the HTTP Status, as you can see here in Google Chrome:
If you didn't have this try..catch code, you'd just get an HTTP Status Error of 400, which means "Bad Request".
So now, with our try..catch in place, I can call my web service from my Angular controller, and look out for such error messages coming back.
$http.get('http://localhost:15021/Service1.svc/getAllCustomerNames')
.then(function (data) {
// We successfully loaded the list of Customer names.
$scope.ListOfCustomerNames = data.GetAllCustomerNamesResult;
}, function (errorResponse) {
// The WCF Web Service returned an error
var HTTPErrorNumber = errorResponse.status;
var HTTPErrorStatusText = errorResponse.statusText;
alert("An error occurred whilst fetching Customer Names\r\nHTTP status code: " + HTTPErrorNumber + "\r\nError: " + HTTPErrorStatusText);
});
Cool, hey ?
Incredibly simple, generic, and easy to add to your services.
Shame some readers thought it was worth voting down. Sorry about that.
You have several options:
1) If you are using WCF, throw a FaultException on the server and catch it on the client. You could, for instance, implement a FaultContract on your service, and wrap the exception in a FaultException. Some guidance to this here.
2) You could use the Windows Server AppFabric which would give you more details to the exception within IIS. (requires some fiddling to get it working, though)
3) Why not implement some sort of server-side logging for the exceptions? Even if to a file, it would be invaluable to you to decipher what is really happening. It is not a good practice (especially for security reasons) to rely on the client to convey the inner workings of the server.

WCF WebApi HttpResponseException Issue

I am trying to throw an HttpResponseException(HttpStatusCode.NotFound) and I am getting the following error
The response message returned by the Response property of this exception should be immediately returned to the client. No further handling of the request message is required.
I have removed all of the code in my method and I am just throwing the exception like this
[WebGet]
public MyData Get()
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
If I change my method to return a HttpResponseMessage I can get it to work correctly, however it does not solve the issue and I am unable to get my authentication operation handler to work without being able to throw a HttpResponseException.
Try using a WebFaultException for returning HTTP Status codes in WCF...
throw new WebFaultException(HttpStatusCode.NotFound);