I have a WCF POST Method - it looks like below:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "UploadReport/{customerId}/{author}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
string UploadReport(string customerId, byte[] fileData, string author);
It is used to upload a Report to an ECM Client I am using.
I was calling this with a WCF Client in another solution by adding the Service reference to the WSDL. So as below:
using (MemoryStream mem = new MemoryStream())
{
ExcelReportGenerator excel = new ExcelReportGenerator();
success = excel.CreateExcelDoc(mem, customerId);
mem.Position = 0;
try
{
using (CustomerClient.UploadClient customerClient = new CustomerClient.UploadClient())
{
customerClient.Endpoint.Binding.SendTimeout = new TimeSpan(0, 10, 0);
uploadReportId = customerClient .UploadReport(customerId.ToString(), mem.ToArray(), userId.ToString());
}
//remaining code removed from brevity
However now I need to make this call from a HttpWebRequest rather than using the generated wcf client.
However, I am wondering how to do this in order to POST the byte array as well as the customer id and author.
I have used something like the below for a simple API GetRequest before
string jsonResponse = string.Empty;
string requestUri = string.Format("{0}", myAPI);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
request.Credentials = new NetworkCredential(userNameWs, passwordWs);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
jsonResponse = reader.ReadToEnd();
reader.Close();
dataStream.Close();
}
IN the above myAPI was loaded from config and looked like below:
http://localhost/myWS/api/Reference/GetAllCarManufacturers
I know to make it hit my WCF Method I would need
request.Method = "POST";
What would I need in order to POST the fileData and hit the Post URL which in the WCF is in the format "UploadReport/{customerId}/{author}
Related
I have a WCF Service that I start up in VS2015. Then Client code in another VS2015.. I keep getting "the remote server returned an error (404) Not Found" Error. When I add parameter to URL "http://localhost:53989/FileShareService.svc/UploadFile/WTM" is works fine but if I add as encoding.GetBytes I get the error.
[ServiceContract]
public interface IFileShareWebService
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "UploadFile/{patron}",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
void UploadFile(string patron);
}
Client Code Not Working:
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = "patron=WTM";
byte[] data = encoding.GetBytes(postData);
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://localhost:53989/FileShareService.svc/UploadFile/WTM");
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
httpWebRequest.ContentLength = 0;
//httpWebRequest.GetRequestStream();
// Code to write data to the stream
using (Stream requestStream = httpWebRequest.GetRequestStream())
{
requestStream.Write(data, 0, data.Length);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Client Code Working:
var httpWebRequest =(HttpWebRequest)WebRequest.Create("http://localhost:53989/FileShareService.svc/UploadFile/WTM");
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
httpWebRequest.ContentLength = 0;
httpWebRequest.GetRequestStream();
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
I have a WCF project that returns a DataSet in XML format. This is in my service contract:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "RunSavedReportByID", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
DataSet RunSavedReportByID(int savedReportID);
I have another project that consumes this service, and I'm trying to get the DataSet back. I call my service like so:
strResults = objUtility.GetData("RunSavedReportByID", JsonConvert.SerializeObject(new { savedReportID = savedReportID }));
GetData looks like this:
public string GetData(string method, string data)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(externalServiceUrl + method);
ASCIIEncoding encoding = new ASCIIEncoding();
var postData = encoding.GetBytes(data);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(postData, 0, data.Length);
}
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8))
{
return reader.ReadToEnd().Trim();
}
}
}
}
}
catch (Exception ex)
{
string error = ex.Message;
}
return null;
}
The string that I get is weird. It looks like this when I save it to a text file:
"\"<DataSet><xs:schema id=\\\"NewDataSet\\\" xmlns:xs=\\\"http:\\/\\/www.w3.org\\/2001\\/XMLSchema\\\" xmlns:msdata=\\\"urn:schemas-microsoft-com:xml-msdata\\\"><xs:element name=\\\"NewDataSet\\\" msdata:IsDataSet=\\\"true\\\" msdata:UseCurrentLocale=\\\"true\\\"><xs:complexType><xs:choice minOccurs=\\\"0\\\" maxOccurs=\\\"unbounded\\\"><xs:element name=\\\"Table\\\"><xs:complexType><xs:sequence><xs:element name=\\\"InvoiceNo\\\" type=\\\"xs:long\\\" minOccurs=\\\"0\\\"\\/><xs:element name=\\\"GuestID\\\" type=\\\"xs:long\\\" minOccurs=\\\"0\\\"\\/><xs:element name=\\\"ConsumerID\\\" type=\\\"xs:long\\\" minOccurs=\\\"0\\\"\\/><xs:element name=\\\"ContactTitleName\\\" type=\\\"xs:string\\\" minOccurs=\\\"0\\\"\\/><xs:element name=\\\"LastName\\\" type=\\\"xs:string\\\" minOccurs=\\\"0\\\"\\/><xs:element name=\\\"FirstName\\\" type=\\\"xs:string\\\" ... blah blah blah ... \\/NewDataSet><\\/diffgr:diffgram><\\/DataSet>\""
Not surprisingly, after I create and XmlDocument and call LoadXml, I get
Data at the root level is invalid. Line 1, position 1.
If I strip out the first and last quotation marks and unescape the string like so
strResults = Regex.Unescape(strResults);
strResults = strResults.Remove(0, 1);
strResults = strResults.Remove(strResults.Length - 1, 1);
then the XML loads fine, so the XML itself is legit.
So after all this exposition, my questions are
1) Why does the string I get back look so weird? What's up with all the extra quotation marks and backslashes?
2) Is there a better way of getting rid of the bad stuff before loading the XML?
I need to write a REST service that accepts XML documents from a client application. I don't have access to the client application and it cannot be changed.
It sends documents using a HTTP POST with a content type of text/xml; charset="UTF-8".
I have tried two different Operation Contracts and they both have different issues...
First my Host code:
private static WebServiceHost _host;
public static void ConnectToHost()
{
string url = ConfigHelper.GetValue("WebService.config", "WebServiceURL");
Uri baseAddress = new Uri(url);
Type instanceType = typeof(CXMLService);
_host = new WebServiceHost(instanceType, baseAddress);
Type contractType = typeof(ICXMLService);
ServiceEndpoint endpoint = _host.AddServiceEndpoint(contractType, new WebHttpBinding(), "Web");
endpoint.Behaviors.Add(new WebHttpBehavior());
_host.Open();
}
If I use this...
[OperationContract]
[WebInvoke(UriTemplate = "SendText")]
Stream SendText(Stream s);
I can receive XML files using a content type of "text/plain" but if I switch it to "text/xml" which is what the client will be sending I get a 400 Bad Request.
If I use this...
[OperationContract]
[WebInvoke(UriTemplate = "SendXML", Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml)]
XElement SendXML(XElement xml);
Then it works with "text/xml" but fails with a 400 Bad Request because the XML has a DOCTYPE element outside of the root. I cannot change this XML file. Here is a sample of the file...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cXML.org/schemas/cXML/1.2.024/cXML.dtd">
<cXML payloadID="32232995#ariba.acme.com"
timestamp="2000-10-12T18:39:09-08:00" xml:lang="en-US">
<Header>
/// data here
</Header>
<Request deploymentMode="test">
// data here
</Request>
</cXML>
Here is a basic way to stream an xml document to WCF service.
Contract:
[OperationContract]
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "ProfileRequest")]
Stream ProfileRequest(Stream value);
Service:
public Stream ProfileRequest(Stream value)
{
StreamReader reader = new StreamReader(value);
string text = reader.ReadToEnd();
XDocument post = XDocument.Parse(text);
XDocument response = ProfileRequest(post);
return new MemoryStream(Encoding.UTF8.GetBytes(response.ToString()));
}
Test Console:
string filePath = "C:\someFile.xml";
XDocument testDoc = XDocument.Load(filePath);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(filePath);
string newDoc = xDoc.InnerXml.ToString();
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(testDoc.ToString());
string localProfile = "http://localhost/WcfService/Service1.svc/ProfileRequest";
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(localProfile);
webrequest.Method = "POST";
webrequest.ContentType = "text/xml";
webrequest.ContentLength = data.Length;
Stream newStream = webrequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();
string strResult = string.Empty;
Encoding enc = System.Text.Encoding.GetEncoding("UTF-8");
StreamReader loResponseStream = new StreamReader(webresponse.GetResponseStream(), enc);
strResult = loResponseStream.ReadToEnd();
loResponseStream.Close();
webresponse.Close();
Console.Write(strResult);
I have created a website using WCF REST Service Template 40(CS) and It has a service method like this:
[WebInvoke(UriTemplate = "CTNotification", Method = "POST", ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
public string CTNotification(Stream contents)
How can I pass json to it ? I can not make the service parameter as string because client will be sending json as stream. How can I make a post call using C# to this service method with content type = application/json
Regards,
Asif Hameed
I'm not sure if you are doing this Synchronously or sync, but here is how to pass your args. The implementation may differ based on the needs of the client
HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create(ServiceAddress + "CTNotification/");
//parameters
byte[] data = Encoding.UTF8.GetBytes(jsonString);
httpWReq.Method = "POST";
httpWReq.ContentType = "application/x-www-form-urlencoded";
httpWReq.ContentLength = data.Length;
httpWReq.Timeout = 1000;
using (Stream newStream = httpWReq.GetRequestStream())
{
newStream.Write(data, 0, data.Length);
}
I am new to restful services and I have been creating a series of simple console apps to better understand. I have a simlple service that I am trying to send data to but I keep getting a 400 bad request error. I know it has to be something simple I overlooked. Any help would be greatly appreciated. Thanks
//service contract
[OperationContract, WebInvoke(Method = "POST", UriTemplate = "Test")]
bool Test(string input);
//service
public bool Test(string input)
{
Console.Out.WriteLine("recieved [" + input + "]");
return true;
}
//host program
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8889/TestImage");
WebServiceHost host = new WebServiceHost(typeof(ImageTestService), baseAddress);
try
{
host.Open();
Console.Out.WriteLine("TestService hosted at {0}", baseAddress.ToString());
Console.Out.WriteLine("hit enter to terminate");
Console.In.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadKey();
}
finally
{
if (host.State == CommunicationState.Faulted)
host.Abort();
else
host.Close();
}
}
}
//client program
// Create the web request
Uri address = new Uri("http://localhost:8889/TestImage/Test");
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
// Set type to POST
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
StringBuilder data = new StringBuilder();
data.Append("input=" + HttpUtility.UrlEncode("12345"));
// Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
postStream.Close();
}
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
}
Not sure that is answers your question - but I have an extension method I have been using for form post:
public static HttpWebResponse DoFormPost(this HttpWebRequest request, string postVals, int timeoutSeconds)
{
request.Method = "POST";
request.Timeout = timeoutSeconds * 0x3e8;
request.ContentType = "application/x-www-form-urlencoded";
request.AllowAutoRedirect = false;
byte[] bytes = Encoding.UTF8.GetBytes(postVals);
request.ContentLength = bytes.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
}
return (HttpWebResponse)request.GetResponse();
}
Or since you tagged WCF, then there is also another similar question:
Getting an http 400 error on calling a restful wcf service using http post
Unfortunately, I'm not sure what's wrong with your code, it looks okay at first glance. I wonder if it's the UriTemplate that you're using. If your method is "Test" and the UriTemplate is "Test", you might need to call it with this URL (two "Test" strings):
Uri address = new Uri("http://localhost:8889/TestImage/Test/Test");
I believe the method name is part of the URL by default, so the template gets applied after that.
With HTTP errors, I use a tool called Fiddler to troubleshoot. If you can create a request that works with the Request Builder, it's just a matter of figuring out how to produce that request via your code.
The WCF service you are calling is expecting the string you are passing to be serialized in XML!
The following has worked for me in the past:
string body = "foo";
string postData = #"<string xmlns='http://schemas.microsoft.com/2003/10/Serialization/'><![CDATA[" + body + "]]></string>";