Microsoft OData Client 6.x with OData service 4.x handle NULL return (404 Not Found) on the client - asp.net-web-api2

I can't seem to figure out how to handle NULL (404 Not Found) on the client when calling an OData function for a given Entity.
Ex> calling service like "Context.Objects.ByKey(1).SomeFunction().GetValue()"
I want to get "NULL" from the service but instead on the client it throws a 404 Not Found exception.
If I alter the service to return "NULL" then I will receive a serialization exception on the server and if I tell the server to return "OK(null)" I will also get a serialization exception.
Here is the server code for the controller
[HttpGet]
public IHttpActionResult SomeFunction([FromODataUri] int key)
{
string something = null;
// Do some check and adjust the variable "something"
if (string.IsNullOrWhiteSpace(something))
{
return NotFound();
}
else
{
return Ok(something);
}
}
And here is the WebApiConfig code
builder.EntityType<SomeObject>().Function("SomeFunction").Returns<string>();
I can't seem to find the "proper" way of handling null values from the odata service when using Microsoft OData client.
Maybe I can wire into the client "ReceivingResponse" event to handle the 404 Not Found some how? Any suggestions...

The default behavior of the OData client is to throw an exception when the OData service returns a 404 File Not Found.
To get around this there is a property on the OData Client generated code called "IgnoreResourceNotFoundException".
Set this property to true and it with not throw an exception.

Related

Why is my .Net Core MVC service returning 200s for non-existent routes?

I have a .net core MVC Web API project (or whatever it's called in .net core now). I have a Message Controller:
[Route("api/[controller]")
public class MessageController
{
Public MessageController()
{}
// This works
[HttpGet]
public IMessage Get()
{
// Do stuff to get a Message
return Message;
}
}
When I call the Get endpoint like so:
GET => http://MyService/api/Message/
I get back the expected message object as JSON and an HTTP 200.
However, when I call a nonexistent endpoint:
GET => http://MyService/api/Message/Foo
I get back empty json [] and an HTTP 200.
Obviously something in the routing is matching on every route and returning 200 rather than matching only on actual routes and returning 404s for anything that doesn't match. So where is the default route which is catching everything defined and how do I kill it?

Apache Http Client Put Request Error

I'm trying to upload a file using the Apache Http Client's PUT method. The code is as below;
def putFile(resource: String, file: File): (Int, String) = {
val httpClient = new DefaultHttpClient(connManager)
httpClient.getCredentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(un, pw))
val url = address + "/" + resource
val put = new HttpPut(url)
put.setEntity(new FileEntity(file, "application/xml"))
executeHttp(httpClient, put) match {
case Success(answer) => (answer.getStatusLine.getStatusCode, "Successfully uploaded file")
case Failure(e) => {
e.printStackTrace()
(-1, e.getMessage)
}
}
}
When I tried running the method, I get to see the following error:
org.apache.http.NoHttpResponseException: The target server failed to respond
at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:101)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:252)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:281)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:247)
at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:219)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:298)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:633)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:454)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
I do not know what has gone wrong? I'm able to do GET requests, but PUT seems not to work! Any clues as to where I should look for?
Look on the server. If GET Works, but PUT does not, then you have to figure out the receiving end.
Also, you may want to write a simple HTML File that has a form with PUT Method in it to rule out your Java Part.
As a sidenode: Its technically possible that something in between stops the request from going through or the response reaching you. Best setup a dummy HTTP Server to do the testing against.
Maybe its also a timeout issue, so the server takes to long to process your PUT.
The connection you are trying to use is a stale connection and therefore the request is failing.
But why are you only seeing an error for the PUT request and you are not seeing it for the GET request?
If you check the DefaultHttpRequestRetryHandler class you will see that by default HttpClient attempts to automatically recover from I/O exceptions. The default auto-recovery mechanism is limited to just a few exceptions that are known to be safe.
HttpClient will make no attempt to recover from any logical or HTTP protocol errors (those derived from HttpException class).
HttpClient will automatically retry those methods that are assumed to be idempotent. Your GET request, but not your PUT request!!
HttpClient will automatically retry those methods that fail with a transport exception while the HTTP request is still being transmitted to the target server (i.e. the request has not been fully transmitted to the server).
This is why you don't notice any error with your GET request, because the retry mechanism handles it.
You should define a CustomHttpRequestRetryHandler extending the DefaultHttpRequestRetryHandler. Something like this:
public class CustomHttpRequestRetryHandler extends DefaultHttpRequestRetryHandler {
#Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if(exception instanceof NoHttpResponseException) {
return true;
}
return super.retryRequest(exception, executionCount, context);
}
}
Then just assign your CustomHttpRequestRetryHandler
final HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setRetryHandler(new CustomHttpRequestRetryHandler());
And that's it, now your PUT request is handled by your new RetryHandler (like the GET was by the default one)

The underlying connection was closed: An unexpected error occurred on a receive. while Using WCF

I am using mvc4 as my web application which inherits a WCF service i have an Entity framework and used Code first for database Now, Entity layer is inherited to both MVC as well as to WCF but Data Access layer is only inherited to the WCF, Now when ever i call the WCF method from my controller the method is called nicely and the method works fine into the WCF and returns the expected result but when it returns result to the MVC application it throws an exception of "The underlying connection was closed: An unexpected error occurred on a receive." can anyone please help me out, following is the code respectively:-
for Controller class
public ActionResult CustomerSearch()
{
APIServiceDaman.Customer ObjTestEn = new APIServiceDaman.Customer();
using (Objjj = new APIServiceDaman.Service1())
{
var ObjTestEn2 = Objjj.GetUserDetails(1, true);
}
return View(ObjTestEn);
}
for WCF:-
public X.Entities.Customer GetUserDetails(int CustomerID)
{
X.Entities.Customer objtest = new X.Entities.Customer();
using (ObjCustomerEvidence = new CustomerManager())
{
objtest = ObjCustomerEvidence.GetCustomerByID(CustomerID);
}
return objtest;
}
for DataAccess Layer:-
public Entities.Customer GetCustomerByID(int ID)
{
return DBContext.Customer.Where(c => c.ID == ID).FirstOrDefault();
}
First of all check your web.config setting for executionTimeout and maxRequestLength on both side WCF and your MVC4 client. for more information on this please refer this below link there is a good answer given by jlchereau, follow this steps and try to check it out again, it might help you out. also try to enable WCF tracing (Tracing) and find out the root of exception it will help you a lot to resolve your issue.
http://velodocaddin.codeplex.com/discussions/40792

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!

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);