I am building a REST service on WCF, and one of the methods I am writing is GetProfile, which will return the profile for a given username. The username will include the user's domain, and so will have the following format: "DOMAIN\username".
I therefore have a service called Profiles.svc, which has the following endpoint set up:
[OperationContract]
[WebGet(UriTemplate = "/{username}", ResponseFormat = WebMessageFormat.Xml)]
IRestResponse GetProfile(String username);
However, when I attempt to visit the service at http://server/profiles.svc/DOMAIN%5cusername (%5c is the urlencoded form of a backslash) I get the following error:
Server error in '/' Application
HTTP Error 400 - Bad Request
This occurs even when there is no code actually defined in my implementation of GetProfile, so I believe the error is being thrown at the point WCF attempts to bind the URI to a method.
Are there some settings I need to add to my web service configuration in order to allow backslashes to be added to URLs in a REST WCF service? Or are backslashes simply not allowed?
I suspect that they are simply not allowed in that part of the url. They are fine in the query string as long as they are encoded. As a general rule i wouldn't put anything in the path part of the url that is invalid in filename (i.e. ?).
Perhaps you could use a different character to deliminate th domain from the username.
You could also seperate the username into domainname and username and use the normal path deliminator '/'. I'm not familar with the this enough to know if this is how you do it for sure, but this would be my best guess.
[OperationContract]
[WebGet(UriTemplate = "/{domainName}/{username}", ResponseFormat = WebMessageFormat.Xml)]
IRestResponse GetProfile(String domainName, String username);
Related
I am integrating with a third party API via a PUT request (required). However the URL is not what I consider standard.
https://standard.com/services/U2FsdGVkX18qfVhkTn7JsiXWA8q4vco7vpU%2BmeKqiXKafdKxfJqsq1ELGFOHIilpoR7VXqUcg89yXiabxjjfVXiRmVqGOffsKw%2BKLp5OU6%2FJZaTyn6BYxi%2F10ndtWFLG2KgxRmm%2BxtgTAopUi6m7wWTnSoAlL8qoS%2F3UbiippOw%3D.
Note that the reservation number isn't in the body nor as a parameter, its just a / then the number.
They have encoded the reservation number (requested via another API call). The issue is I'm using HttpRequestMessage, this decodes the %2F to /. Meaning it fails. I have tried double encoding the special characters but this isn't returning a consistent response, sometimes it fails other times it works (using different reservation numbers, only the %2F is double encoded). Is there a way to stop HttpRequestMessage decoding part of the URL?
I have tried encoding/decoding but it always gets stripped out here (unless double encoded:
var path = "https://standard.com/services/U2FsdGVkX18qfVhkTn7JsiXWA8q4vco7vpU%2BmeKqiXKafdKxfJqsq1ELGFOHIilpoR7VXqUcg89yXiabxjjfVXiRmVqGOffsKw%2BKLp5OU6%2FJZaTyn6BYxi%2F10ndtWFLG2KgxRmm%2BxtgTAopUi6m7wWTnSoAlL8qoS%2F3UbiippOw%3D";
var requestMessage = new HttpRequestMessage(HttpMethod.PUT, path);
var requestMessage = (HttpWebRequest)WebRequest.Create(path);
var requestMessage = new HttpRequestMessage(method, new Uri(path));
Update: This was a design decision made by Microsoft:
https://connect.microsoft.com/VisualStudio/feedback/details/511010/erroneous-uri-parsing-for-encoded-reserved-characters-according-to-rfc-3986
The solution from their point of view is to add a setting in the
web.config. But this is a class library and therefore used by more
than one project. I don't want to alter that unless I really have to
This was a design decision made by Microsoft: https://connect.microsoft.com/VisualStudio/feedback/details/511010/erroneous-uri-parsing-for-encoded-reserved-characters-according-to-rfc-3986
I am sending a POST request to a WCF Web service using fiddler, and the service responds with HTTP 400: The request has an invalid header name.
The post request looks like this:
User-Agent: Fiddler
Host: localhost:49392
Content-Type: application/json
Content-Length: 0
{ "clientFirstName" : "John"}
My endpoint is defined as follows:
[OperationContract]
[System.ServiceModel.Web.WebInvoke
(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = System.ServiceModel.Web.WebMessageFormat.Json,
BodyStyle = System.ServiceModel.Web.WebMessageBodyStyle.Wrapped,
UriTemplate = "MakeReservation")]
String MakeReservation(Stream reservationStream);
MORE
First of all, the JSON was in the wrong pane. I moved it to the Request Body pane.
I changed the prototype of the function to take a String instead of Stream as the input parameter. The service now accepts my call and returns 200, but in the debugger I see that the input parameter String is null. When I change it back to Stream, I get 400 again.
YET MORE
Enable tracing gives me at trace file with the following message:
Incoming message for operation 'MakeReservation' (contract 'ITalLimoService' with namespace
'http://tempuri.org/') contains an unrecognized http body format value 'Json'. The expected body
format value is 'Raw'. This can be because a WebContentTypeMapper has not been configured on the
binding. See the documentation of WebContentTypeMapper for more details.
As noted int the WebInvoke definitiuon, both the RequestFormat and ResponseFormat are set to WebMessageFormate.Json. Why is IIS complaining about this?
I don't know why this works, but for some reason removing the following line from the fiddler Composer did the trick:
Content-Type: application/json
And that is that. I would give points for an explanation.
I know this post is old. But very strange, when I removed the header "application/json" it worked.
Has it got to do with server setup?
The request could not be understood by the server due to deformed syntax. The client SHOULD NOT repeat the request without modifications.If request to your server with data that is in the correct format, but its bad data. eg: a Posted String value to an API endpoint that expected a String value; but, the value of the string contained data that was something else.
The syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions. For example, this error condition may occur if an XML request body contains syntactically correct but semantically wrong XML instructions.
I'm writing a client against a vendor's webservice, using WCF in Visual Studio 2010. I have no ability to change their implementation or configuration.
Running against an install on their test server, I had no problems. I added a service reference from their wsdl, set the url in code, and made the call:
var client = new TheirWebservicePortTypeClient();
client.Endpoint.Address = new System.ServiceModel.EndpointAddress(webServiceUrl);
if (webServiceUsername != "")
{
client.ClientCredentials.UserName.UserName = webServiceUsername;
client.ClientCredentials.UserName.Password = webServicePassword;
}
TheirWebserviceResponse response = client.TheirOperation(myRequest);
Simple and straightforward. Until they moved it to their production server and configured it to use https. Then I got this error:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm='.
So I went looking for help. I found this: Can not call web service with basic authentication using wcf.
The approved answer suggested this:
BasicHttpBinding binding = new BasicHttpBinding();
binding.SendTimeout = TimeSpan.FromSeconds(25);
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
EndpointAddress address = new EndpointAddress(your-url-here);
ChannelFactory<MyService> factory =
new ChannelFactory<MyService>(binding, address);
MyService proxy = factory.CreateChannel();
proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "password";
Which also seemed simple enough. Except for my trying to figure out which of the multitude of classes and interfaces that were generated from the wsdl to make the service reference I should use in place of the "MyService", above.
My first try was to use "TheirWebservicePortTypeClient" - the class I had instantiated in the previous version. That gave me a runtime error:
The type argument passed to the generic ChannelFactory class must be an interface type.
So I dug into the generated code, a bit more. I saw this:
public partial class TheirWebservicePortTypeClient
:
System.ServiceModel.ClientBase<TheirWebservicePortType>,
TheirWebservicePortType
{
...
}
So I tried instantiating ChannelFactory<> with TheirWebservicePortType.
This gave me compile-time errors. The resulting proxy didn't have a ClientCredentials member, or a TheirOperation() method.
So I tried "System.ServiceModel.ClientBase".
Instantiation ChannelFactory<> with it still gave me compile-time errors. The resulting proxy did have a ClientCredentials member, but it still didn't have a TheirOperation() method.
So, what gives? How do I pass a username/password to an HTTPS webservice, from a WCF client?
==================== Edited to explain the solution ====================
First, as suggested, instantiation the factory with TheirWebservicePortType, adding the username and password to the factory.Credentials, instead of to proxy.ClientCredentials worked fine. Except for one bit of confusion.
Maybe it's something to do with the odd way the wsdl is written, but the client class, TheirWebservicePortTypeClient, defined TheirOperation as taking a Request argument and returning a Response result. The TheirWebservicePortType interface defined TheirOperation as taking a TheirOperation_Input argument and returning a TheirOperation_Output result, where TheirOperation_Input contained a Request member and TheirOperation_Output contained a Response member.
In any case, if I constructed a TheirOperation_Input object from the passed Request, the call to the proxy succeeded, and I could then extract the contained Response object from the returned TheirOperation_Output object:
TheirOperation_Output output = client.TheirOperation(new TheirOperation_Input(request));
TheirWebserviceResponse response = output.TheirWebserviceResponse;
You add the credentials to the ChannelFactory Credentials property
I have a wcf service defined like this:
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json)]
public CreateOrderResponse CreateOrder(CreateOrderRequest request)
The request parameter is populated fine, but inside my method a what to access HttpContext.Current.Request.InputStream to get the raw post body but the InputStream is empty, InputStream.Lenght is 0.
My question is why is Request.InputStream empty when the request parameter is populated fine from the post request?
You need to use the CreateOrderRequest instance and it's associated properties.
As far as I know, and I may be wrong, the Inputstream would always be null as it has been processed prior to being passed to your WCF method. See this link for more information Capturing raw HTTP POST Data during Exception
I have a pretty simple WCF service set up with a method similar to:
[OperationContract]
[WebGet(UriTemplate = "/GetById/{id}")]
ResponseSingle<BinderViewModel> GetById(string id);
When I try and hit it with a GUID like...
http://localhost/services/myservicename.svc/GetById/5c3f04d7-f96e-4acd-847b-6da5937e
It returns a 500 and an exception stating:
Length cannot be less than zero. Parameter name: length
If I remove the UriTemplate and instead hit it as:
http://localhost/services/myservicename.svc/GetById?id=5c3f04d7-f96e-4acd-847b-6da5937e
It works fine.
I've done a bit of reading and it looks like the request will fall over when it grows > a certain length.
Wondering if anyone else has been bitten by this previously and if so had any luck resolving it?
Cheers,
Tim
[WebGet(UriTemplate = "/GetById/{id}")]
Should be:
[WebGet(UriTemplate = "/GetById?id={id}"]
Adding more information (as I was confused for a second), /Action/{variable} is for the path of the service. I.e., /GetBy/ID or /GetBy/Name
Whereas, the method is expecting a value to complete processing of the service, so that will have to be a query in the syntax ?CaseSenstiveMethodParameterName={queryParameter}
MSDN URL Template Help