Wcf Client: Passing XML string in the WCF REST service using WebInvoke - wcf

With out parameter for Display method it is working in browser i.e http://localhost:2617/UserService.svc/test
When i add one parameter i am unable to browse it also.
I have the following contract.
[ServiceContract]
public interface IUserService
{
[OperationContract]
[WebInvoke(Method="PUT",UriTemplate = "/tes/{name}",
BodyStyle=WebMessageBodyStyle.WrappedRequest)]
string Display(string name);
}
public string Display(string name)
{
return "Hello, your test data is ready"+name;
}
I am trying to call using the following code
string url = "http://localhost:2617/UserService.svc/test"; //newuser
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
string xmlDoc1 = "<Display xmlns=\"\"><name>shiva</name></Display>";
req.Method = "POST";
req.ContentType = "application/xml";
byte[] bytes = Encoding.UTF8.GetBytes(xmlDoc1);
req.GetRequestStream().Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
Stream responseStream = response.GetResponseStream();
var streamReader = new StreamReader(responseStream);
var soapResonseXmlDocument = new XmlDocument();
soapResonseXmlDocument.LoadXml(streamReader.ReadToEnd());
I am unable to get output for that.please help me on this.

There are a few things that are not quite right in your code.
Client
On the client you need to specify the namespace to be tempuri, since you have not declared an explicit one, so your client code would need to be this:
string url = "http://localhost:2617/UserService.svc/test"; //newuser
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
string xmlDoc1 = "<Display xmlns=\"http://tempuri.org/\"><name>shiva</name></Display>";
req.Method = "POST";
req.ContentType = "application/xml";
byte[] bytes = Encoding.UTF8.GetBytes(xmlDoc1);
req.GetRequestStream().Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
Stream responseStream = response.GetResponseStream();
var streamReader = new StreamReader(responseStream);
var soapResonseXmlDocument = new XmlDocument();
soapResonseXmlDocument.LoadXml(streamReader.ReadToEnd());
Service
On the service the UriTemplate is not quite right - you are specifying /tes/{name} so that will be expecting a URL like http://localhost:2617/UserService.svc/tes/shiva but you are wanting to post XML data to it in the body so you should change that to UriTemplate = "/test" (I am assuming you meant test and not tes as in your question).
Also, the method should be POST if you are wanting to POST data to it (the client needs to match the service and I am assuming what you have on the client is what you want).
So, in conclusion, your IUserService should look like this:
[ServiceContract]
public interface IUserService
{
[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "/test",
BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string Display(string name);
}

You still need to create a class
public class Test
{
public string name { get; set; }
}
You can also use fiddler to check if {name:999} could be passed as a parameter.

Related

How do I login into a website using WebClient in vb.Net? [duplicate]

I've previously used a CookieContainer with HttpWebRequest and HttpWebResponse sessions, but now, I want to use it with a WebClient. As far as I understand, there is no built-in method like there is for HttpWebRequests (request.CookieContainer). How can I collect cookies from a WebClient in a CookieContainer?
I googled for this and found the following sample:
public class CookieAwareWebClient : WebClient
{
private readonly CookieContainer m_container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
HttpWebRequest webRequest = request as HttpWebRequest;
if (webRequest != null)
{
webRequest.CookieContainer = m_container;
}
return request;
}
}
Is this the best way to do it?
WebClient wb = new WebClient();
wb.Headers.Add(HttpRequestHeader.Cookie, "somecookie");
From Comments
How do you format the name and value of the cookie in place of "somecookie" ?
wb.Headers.Add(HttpRequestHeader.Cookie, "cookiename=cookievalue");
For multiple cookies:
wb.Headers.Add(HttpRequestHeader.Cookie,
"cookiename1=cookievalue1;" +
"cookiename2=cookievalue2");
Yes. IMHO, overriding GetWebRequest() is the best solution to WebClient's limited functionalty. Before I knew about this option, I wrote lots of really painful code at the HttpWebRequest layer because WebClient almost, but not quite, did what I needed. Derivation is much easier.
Another option is to use the regular WebClient class, but manually populate the Cookie header before making the request and then pull out the Set-Cookies header on the response. There are helper methods on the CookieContainer class which make creating and parsing these headers easier: CookieContainer.SetCookies() and CookieContainer.GetCookieHeader(), respectively.
I prefer the former approach since it's easier for the caller and requires less repetitive code than the second option. Also, the derivation approach works the same way for multiple extensibility scenarios (e.g. cookies, proxies, etc.).
This one is just extension of article you found.
public class WebClientEx : WebClient
{
public WebClientEx(CookieContainer container)
{
this.container = container;
}
public CookieContainer CookieContainer
{
get { return container; }
set { container= value; }
}
private CookieContainer container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest r = base.GetWebRequest(address);
var request = r as HttpWebRequest;
if (request != null)
{
request.CookieContainer = container;
}
return r;
}
protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
{
WebResponse response = base.GetWebResponse(request, result);
ReadCookies(response);
return response;
}
protected override WebResponse GetWebResponse(WebRequest request)
{
WebResponse response = base.GetWebResponse(request);
ReadCookies(response);
return response;
}
private void ReadCookies(WebResponse r)
{
var response = r as HttpWebResponse;
if (response != null)
{
CookieCollection cookies = response.Cookies;
container.Add(cookies);
}
}
}
The HttpWebRequest modifies the CookieContainer assigned to it. There is no need to process returned cookies. Simply assign your cookie container to every web request.
public class CookieAwareWebClient : WebClient
{
public CookieContainer CookieContainer { get; set; } = new CookieContainer();
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest request = base.GetWebRequest(uri);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = CookieContainer;
}
return request;
}
}
I think there's cleaner way where you don't have to create a new webclient (and it'll work with 3rd party libraries as well)
internal static class MyWebRequestCreator
{
private static IWebRequestCreate myCreator;
public static IWebRequestCreate MyHttp
{
get
{
if (myCreator == null)
{
myCreator = new MyHttpRequestCreator();
}
return myCreator;
}
}
private class MyHttpRequestCreator : IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
var req = System.Net.WebRequest.CreateHttp(uri);
req.CookieContainer = new CookieContainer();
return req;
}
}
}
Now all you have to do is opt in for which domains you want to use this:
WebRequest.RegisterPrefix("http://example.com/", MyWebRequestCreator.MyHttp);
That means ANY webrequest that goes to example.com will now use your custom webrequest creator, including the standard webclient. This approach means you don't have to touch all you code. You just call the register prefix once and be done with it.
You can also register for "http" prefix to opt in for everything everywhere.

Dealing with WebMessageBodyStyle.Wrapped when making a GET request with RestSharp

I have a simple object:
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
that is being returned from a WCF service with the following Operational Contract:
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "/Countries/{aId}")]
[return: MessageParameter(Name = "Country")]
Country Country(string aId);
Basically the object is wrapped inside a Country:{} block which is what I want. On the client side I do the following:
private void RequestPrepare(out RestClient aRestClient, out RestRequest aRestRequest, string aRequestUri, Method aRequestMethod = Method.GET)
{
aRestClient = new RestClient(BASE_URL);
aRestRequest = new RestRequest(aRequestUri, aRequestMethod);
aRestRequest.AddHeader("Accept", "application/json");
}
and call like so:
RestClient restClient;
RestRequest restRequest;
RequestPrepare(out restClient, out restRequest, "Countries/{aId}");
restRequest.AddUrlSegment("aId", "1"); // replaces matching token in request.Resource
var restResponse = restClient.Execute<Country>(restRequest);
List<Country> listCountry = new List<Country>();
listCountry.Add(new Country {Id = restResponse.Data.Id, Name = restResponse.Data.Name});
return listCountry;
the JSON response is:
Content = "{\"Country\":{\"Id\":1,\"Name\":\"Australia\"}}"
so basically restResponse.Data.Id and restResponse.Data.Name do not contain valid data because of the "Country" wrapping.
1) So how do I configure RestSharp to deal with the Country{} wrap?
2) As a secondary question how do I make the Restsharp call so that it will automatically deserialise List

WCF Interoperability with other services, content type is text/html

I am trying to create a WCF client that operates with an http rest endpoint not based on Microsoft technologies. My WCF-foo is pretty weak, so I don't understand what I am doing incorrectly... I've created a service contract that looks like this...
[ServiceContract]
public interface IFilters
{
[OperationContract]
[WebGet(UriTemplate = "/api/filter.getavailable.xml?api_user={username}&api_key={password}")]
String GetAvailableFilters(String username, String password);
}
Which I try and run like this...
public String Run(String username, String password)
{
var binding = new BasicHttpBinding();
binding.MessageEncoding = WSMessageEncoding.Text;
binding.Security.Mode = BasicHttpSecurityMode.Transport;
var endpointAddress = new EndpointAddress("https://sendgrid.com");
IFilters proxy = ChannelFactory<IFilters>.CreateChannel(binding, endpointAddress);
var result = "";
using (proxy as IDisposable)
{
result = proxy.GetAvailableFilters(username, password);
}
return result;
}
When I run this code, I get an exception that says...
The content type text/html; charset=utf-8 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the response were: ...
Now if I just try and access this from a web browser (with different credentials), I get the xml doc I'm looking for...
https://sendgrid.com/api/filter.getavailable.xml?api_user=foo&api_key=bar
what am I doing incorrectly?
Edit:
This was the final working solution...
public Filters Run(String username, String password)
{
var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
var endpointAddress = new EndpointAddress("https://sendgrid.com");
var factory = new ChannelFactory<IFilters>(binding, endpointAddress);
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
var proxy = factory.CreateChannel();
using (proxy as IDisposable)
{
var results = proxy.GetAvailableFilters(username, password);
return results;
}
}
On the client side you are using BasicHttpBinding which is a SOAP binding not a REST binding. You should try using the WebClient class instead
http://msdn.microsoft.com/en-us/library/system.net.webclient.aspx
or WebChannelFactory
http://msdn.microsoft.com/en-us/library/bb908674.aspx

Simple WCF POST with Uri Template

I thought this would be incredibly simple, but I must be missing something. I am trying to make a simple WCF POST request in conjunction with a UriTemplate. I have read numerous examples where people use a stream paramater as the last paramater, and this is supposed to pick up the POST body. I can only get this to work if the stream is the only paramater.
I've gone back to basics with a simple Hello World service.
Here is my code on the client
static string Test()
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:1884/MyAPI/Service.svc/HelloWorld");
req.Method = "POST";
req.ContentType = "text/plain";
Stream reqStream = req.GetRequestStream();
byte[] fileToSend = System.Text.UTF8Encoding.UTF8.GetBytes("sometext");
reqStream.Write(fileToSend, 0, fileToSend.Length);
reqStream.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
var sr = new StreamReader(resp.GetResponseStream());
return sr.ReadToEnd();
}
And this is the code on the service
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "HelloWorld")]
Stream HelloWorld(Stream content);
}
public Stream HelloWorld(Stream content)
{
var sr = new StreamReader(content);
string text = sr.ReadToEnd();
return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World! " + text));
}
This all works fine. Then I make this change:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "HelloWorld/test/{test}")]
Stream HelloWorld(string test, Stream content);
}
public Stream HelloWorld(string test, Stream content)
{
var sr = new StreamReader(content);
string text = sr.ReadToEnd();
return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World! " + text + test));
}
And change the client code to hit HelloWorld/test/sometext
I get a 500 Internal Server Error. I've tried about 10 different variations including using a ?key=value type UriTemplate, returning strings instead of streams etc, and no luck.
Feels like I'm missing some tiny little thing that is going to make this work, as I have seen countless examples of exactly this all over the web. Theirs works, mine doesn't.
Any ideas?
I am not sure what went wrong, but after trying everything, I resolved this by creating a new project and copying all the code over. Never worked out what the differences were, maybe something got corrupted
Edit: in the end we discovered we had to specify WebServiceHostFactory in the Service.svc. This was there by default in the new project
When streaming, the Stream must be the only parameter: http://msdn.microsoft.com/en-us/library/ms789010.aspx
You may be able to use message headers: Add filename and length parameter to WCF stream when Transfermode = Stream
You can use new single file WCF model to configure and adjust endpoint behaviour. I combined your contract and service class into one file to show you how to do this.
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;
namespace StreamService
{
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MergedEndpoint
{
[WebGet(RequestFormat = WebMessageFormat.Xml, UriTemplate = "Data/{someid}",
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public string GetData(string someid)
{
return string.Format("You entered: {0}", someid);
}
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, UriTemplate = "HelloWorld",
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public Stream HelloWorld1(Stream content)
{
var sr = new StreamReader(content);
string text = sr.ReadToEnd();
return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World from single file! " + text));
}
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, UriTemplate = "HelloWorld/test/{testparam}",
ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public Stream HelloWorld2(string testparam, Stream content)
{
var sr = new StreamReader(content);
string text = sr.ReadToEnd();
return new System.IO.MemoryStream(Encoding.UTF8.GetBytes("Hello World from single file! " + testparam+ text));
}
}
}
Input parameters need to be same name as method params. Their type is also string. You need to do the conversion if you want different input param.
You need to create WCf project and add Global.asax file with routing info for this file. You may need to add reference to System.ServiceModel.Activation to setup routing.
Example:
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
RouteTable.Routes.Add(new ServiceRoute("MergedEndpoint", new WebServiceHostFactory(), typeof(MergedEndpoint)));
}
Your Client code has one change to content type.
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost:55166/MergedEndpoint/HelloWorld/test/234");
req.Method = "POST";
//req.ContentType = "text/plain";
req.MediaType = "HTTP/1.1";
req.ContentType = "application/json; charset=utf-8";
Stream reqStream = req.GetRequestStream();
byte[] fileToSend = System.Text.UTF8Encoding.UTF8.GetBytes("sometext");
reqStream.Write(fileToSend, 0, fileToSend.Length);
reqStream.Close();
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
var sr = new StreamReader(resp.GetResponseStream());
string outp = sr.ReadToEnd();
Console.WriteLine("Response:"+outp);
You can still read the raw content even if it is set to Json type.

text/xml return from rest call

When I make a standard Get Request call to a restful wcf service it returns with a content type of "application/xml". A vendor is asking we send with a content type of "text/xml". How do I switch this in wcf? Is it an attribute?
The call is this:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, Namespace = "")]
[XmlSerializerFormat(Style = OperationFormatStyle.Document, Use=OperationFormatUse.Literal)]
public class Player
{
[WebGet(UriTemplate = "{id}")]
public string GetTestDetailsRequest(string id)
{
TestService.TestServiceClient testServiceClient = new TestServiceClient();
string xml = testServiceClient.GetTestDetailsRequest(Guid.Parse(id));
return xml;
}
}
Don't try and use WCF to call RESTful services. Just use HttpWebRequest or HttpClient, that way you will have control over your request.
You can override the content type:
WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";