SharePoint Rest Api - 403 when trying to update list item - rest

From a C# library I need to use the SP rest Api to upload a document to a document library then set properties for it.
I almost have this working by making the following sequence of calls:
Post to /contextinfo to get the FormDigestValue
Post the binary to /Files/Add including the digest in the header property X-RequestDigest
Get /ListItemAllFields the digest in the header property X-RequestDigest
The next call is a Post to _api/web/lists/GetByTitle('library name')/Items(157)
The same digest value is included in the header property X-RequestDigest as can be seen below:
POST
https://xxx.uk/_api/web/lists/GetByTitle('AssetMgmtEfilesDemo')/Items(157) HTTP/1.1
Accept: application/json, application/xml; odata=verbose
X-HTTP-Method: MERGE
IF-MATCH: *
X-RequestDigest: 0x01426A9818F7145E12BC2E99246C7E00AC1A3905D27204C783107FDDE806D2629171FAD8DCC61008E109DD9948BEB4208DC62107B2336B1228ABA143A2D5B3C6,19 Feb 2019 15:20:44 -0000
Content-Type: application/json; charset=utf-8
Host: xxx.uk
Content-Length: 359
Expect: 100-continue
{
__metadata":{
"type":"SP.Data.AssetMgmtEfilesDemoItem"
},
"UPRN":"U1",
"KeystoneDocType":"Document"
}
My problem is that for this request, I get a "403 forbidden" response.
Can anyone see where I went wrong?

Did you try getting a fresh new form digest value before making the post call ? form digest value do expire after some time (default 30 mins).
You can also check your permission on the specific list.

Sample code for your reference, call Rest API in C# code, reference System.Web.Extensions dll:
using System.Net;
using System.IO;
using System.Web.Script.Serialization;
static void Main(string[] args)
{
UpdateListItem();
}
public static string GetFormDigest()
{
string formDigest = null;
string resourceUrl = "http://sp/sites/dev/_api/contextinfo";
HttpWebRequest wreq = HttpWebRequest.Create(resourceUrl) as HttpWebRequest;
wreq.UseDefaultCredentials = true;
wreq.Method = "POST";
wreq.Accept = "application/json;odata=verbose";
wreq.ContentLength = 0;
wreq.ContentType = "application/json";
string result;
WebResponse wresp = wreq.GetResponse();
using (StreamReader sr = new StreamReader(wresp.GetResponseStream()))
{
result = sr.ReadToEnd();
}
var jss = new JavaScriptSerializer();
var val = jss.Deserialize<Dictionary<string, object>>(result);
var d = val["d"] as Dictionary<string, object>;
var wi = d["GetContextWebInformation"] as Dictionary<string, object>;
formDigest = wi["FormDigestValue"].ToString();
return formDigest;
}
public static void UpdateListItem()
{
string result = string.Empty;
Uri uri = new Uri("http://sp/sites/dev/_api/web/lists/getbytitle('AssetMgmtEfilesDemo')/items(1)");
HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(uri);
wreq.Credentials = CredentialCache.DefaultNetworkCredentials;
wreq.Method = "POST";
wreq.Accept = "application/json; odata=verbose";
wreq.ContentType = "application/json; odata=verbose";
wreq.Headers.Add("X-HTTP-Method", "MERGE");
wreq.Headers.Add("IF-MATCH", "*");
wreq.Headers.Add("X-RequestDigest", GetFormDigest());
string stringData = "{'__metadata': { 'type': 'SP.Data.AssetMgmtEfilesDemoItem' }, 'Title': 'UpdatedViaRest','UPRN':'U1','KeystoneDocType':'Image'}";
wreq.ContentLength = stringData.Length;
StreamWriter writer = new StreamWriter(wreq.GetRequestStream());
writer.Write(stringData);
writer.Flush();
WebResponse wresp = wreq.GetResponse();
using (StreamReader sr = new StreamReader(wresp.GetResponseStream()))
{
result = sr.ReadToEnd();
}
}

Related

Error while reading body of request message through JSON

I need to read content of message from the request body in WCF REST service like -
SERVICE SIDE CODE
string request = Encoding.UTF8.GetString(OperationContext.Current.RequestContext.RequestMessage.GetBody<byte[]>());
But I am getting an error on the service side, no matter what I try:
Expecting element 'base64Binary' from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'.. Encountered 'Element' with name 'Human', namespace 'http://numans.hr-xml.org/2007-04-15'.
and the service contract is defined as:
//[OperationContract(Name = "LoadMessages", IsOneWay = true)]
[WebInvoke(Method = "POST",
UriTemplate = "/LoadMessages",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare)]
[Description("Inbound Message")]
void LoadMessages();
and the implementation is as:
public void LoadMessages()
{
string content = string.Empty;
//var request = OperationContext.Current.RequestContext.RequestMessage.GetBody<FileState>();
string request = Encoding.UTF8.GetString(OperationContext.Current.RequestContext.RequestMessage.GetBody<byte[]>());
}
CLIENT SIDE CODE
Content that I'm sending is:
string jsonData = "{ \"categoryid\":\"" + file.CategoryId + "\",\"fileId\":\"" + file.FileId + "\" }";
I tried many options to send data from the client like:
var buffer = System.Text.Encoding.UTF8.GetBytes(jsonData);
var content = new ByteArrayContent(buffer);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
and also tried this:
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
Posting request:
HttpResponseMessage executionResult = httpClient.PostAsync($"{url}/LoadMessages", content).Result;
I also tried serializing/de-serializing at client/server end, but that also is not working.
Can someone please suggest code samples what I can try that might work? Or point out what am I doing wrong.
A few more examples of what I tried with the JSON data :
var jsonData = JsonConvert.SerializeObject(data, Formatting.Indented);
var details = JObject.Parse(data);
Pasting my client side function for clarity:
HttpClient httpClient = new HttpClient(new HttpClientHandler());
HttpStatusCode statusCode = HttpStatusCode.OK;
string auditMessage = string.Empty;
using (httpClient)
{
var url = ConfigurationManager.AppSettings["APIURL"];
try
{
string jsonData = "{ \"categoryid\":\"" + file.CategoryId + "\",\"fileId\":\"" + file.FileId + "\" }";
//var jsonData = JsonConvert.SerializeObject(data, Formatting.Indented);
//var details = JObject.Parse(data);
//var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
var buffer = System.Text.Encoding.UTF8.GetBytes(jsonData);
var content = new ByteArrayContent(buffer);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage executionResult = httpClient.PostAsync($"{url}/LoadMessages", content).Result;
statusCode = executionResult.StatusCode;
if (statusCode == HttpStatusCode.Accepted)
{
file.Status = "Success";
}
}
catch (Exception ex)
{
}
}
Here is my demo:
This is the interface document of the service:
This is the request:
class Program
{
static void Main(string[] args)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:8012/ServiceModelSamples/service/user");
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-16";
string Json = "{\"Email\":\"123\",\"Name\":\"sdd\",\"Password\":\"sad\"}";
request.ContentLength = Encoding.UTF8.GetByteCount(Json);
Stream myRequestStream = request.GetRequestStream();
StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
myStreamWriter.Write(Json);
myStreamWriter.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream myResponseStream = response.GetResponseStream();
//myResponseStream.ResponseSoapContext
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
string retString = myStreamReader.ReadToEnd();
myStreamReader.Close();
myResponseStream.Close();
Console.WriteLine(retString);
Console.ReadKey();
}
}
Feel free to let me know if the problem persists.
UPDATE
Define the Test class:
[DataContract]
public class Test {
[DataMember]
public string categoryid { get; set; }
[DataMember]
public string fileId { get; set; }
}
the implementation is as:
public void LoadMessages(Test test)
{
Test dataObject = OperationContext.Current.RequestContext.RequestMessage.GetBody<Test>(new DataContractJsonSerializer(typeof(Test)));
Console.WriteLine(dataObject.categoryid);
}

How to send the authentication cookie WebRequest and receive the response in JIRA through REST api?

all
I am working on JIRA, i am sending the authentication request from saparate code and i am getting the response, later i need to fetch all issues from the JIRA than i am sending the request that time i am getting the 401 (Unauthorized) while i am sending the same username and password with gZip compression.
my first request code is following where from i am getting the proper response as authenticated.
string urll = ConfigurationManager.AppSettings["globalUrlForLP"];
HttpWebRequest request;
WebResponse response;
String uri;
LpResponse lp_response;
uri = urll + url;
request = WebRequest.Create(uri) as HttpWebRequest;
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = verb;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.Headers.Set("Authorization", Convert.ToBase64String(Encoding.ASCII.GetBytes(this.Username + ":" + this._password)));
if (null != data)
{
request.ContentType = "application/json";
String jsonPayload = JsonConvert.SerializeObject(data);
byte[] jsonPayloadByteArray = Encoding.ASCII.GetBytes(jsonPayload.ToCharArray());
request.GetRequestStream().Write(jsonPayloadByteArray, 0, jsonPayloadByteArray.Length);
}
lp_response = new LpResponse();
try
{
response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
lp_response.response = reader.ReadToEnd();
}
catch (Exception e)
{
lp_response.error = e;
}
return lp_response;
}
from it i am getting response as following.
{
"session": {
"name": "JSESSIONID",
"value": "12345678901234567890"
},
"loginInfo": {
"failedLoginCount": 10,
"loginCount": 127,
"lastFailedLoginTime": "2014-10-28T06:52:52.211+0000",
"previousLoginTime": "2014-10-28T06:52:52.211+0000"
}
}
Now come to the point, I want to get all projects from the JIRA for that i written following code and i am getting here 401 Unathorized. After getting this i read the JIRA REST Api documentation and there i found following.
"Returns information about the caller's session if the caller is authenticated.
Note that the response contains the Set-Cookie HTTP headers that must be honoured by the caller. If you are using a cookie-aware
HTTP client then it will handle all Set-Cookie headers automatically. This is important because setting the JSESSIONID cookie alone may
not be sufficient for the authentication to work."
so please suggest me what i need to do more with following code ?
my Failure code is following.
string url = ConfigurationManager.AppSettings["urlAllJiraProject"];
LpResponse res = new LpResponse();
HttpWebRequest request;
WebResponse response;
List<AllJiraProject> jiraproject = new List<AllJiraProject>();
request = WebRequest.Create(url) as HttpWebRequest;
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "GET";
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
request.Headers.Set("Authorization", Convert.ToBase64String(Encoding.ASCII.GetBytes(userNamejira + ":" + passwordjira)));
LpResponse lp_response = new LpResponse();
try
{
response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
lp_response.response = reader.ReadToEnd();
jiraproject = (List<AllJiraProject>)JsonConvert.DeserializeObject<List<AllJiraProject>>(lp_response.response.ToString());
}
catch (Exception e)
{
lp_response.error = e;
}
return jiraproject;
The accepted answer uses basic authentication and not a cookie. When requesting the cookie you don't need add any authorization to the headers. This method will accept a json string with the user name and password and the URL. It will return the cookie values.
public async Task<JiraCookie> GetCookieAsync(string myJsonPass, string JiraCookieEndpointUrl)
{
using (var client = new HttpClient())
{
var response = await client.PostAsync(
JiraCookieEndpointUrl,
new StringContent(myJsonPass, Encoding.UTF8, "application/json"));
var json = response.Content.ReadAsStringAsync().Result;
var jiraCookie= JsonConvert.DeserializeObject<JiraCookie>(json);
return jArr;
}
}
public class JiraCookie
{
public Session session { get; set; }
}
public class Session
{
public string name { get; set; }
public string value { get; set; }
}
When I call it using url: http://[baseJiraUrl]/rest/auth/1/session it returns the following JSON response:
{
"session" : -{
"name" : JSESSIONID,
"value" : cookieValue
}
Keep in mind the URL above is valid in the version of JIRA I'm using and may vary depending on which version you're using.
Read the JIRA API documentation for the correct URL for the version you are using.
Check out this answer on how add cookies to your HttpClient request.
How do I set a cookie on HttpClient's HttpRequestMessage
I got it, my code does not have Basic authentication into the header, while API demands the Basic authentication, so i replaced my one line with following two lines.
Replaced line
request.Headers.Set("Authorization", Convert.ToBase64String(Encoding.ASCII.GetBytes(userNamejira + ":" + passwordjira)));
Replaced By
byte[] authBytes = Encoding.UTF8.GetBytes("user:password".ToCharArray());
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(authBytes);
Jira has three type of authentications, this one from Basic authentication, it is easy to implement, but i had no idea how to implement authentication from cookie.

How to add new account in Quickbooks

Below is the code I am using to try to add a new account to QuickBooks online. I am getting a (400) Bad Request. Can anyone help me with this.
HttpWebRequest httpWebRequest =
WebRequest.Create("https://sandbox-quickbooks.api.intuit.com/v3/company/xxxxxxxxxxx/account")
as HttpWebRequest;
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("Authorization", GetDevDefinedOAuthHeader(httpWebRequest, ConsumerKeyQb, ConsumerSecQb, AccessKey, AccessSec));
httpWebRequest.ContentType = "application/json";
httpWebRequest.Accept = "application/xml";
string json = "{\"AccountType\":\"Accounts Receivable\",\"Name\":\"MySampleAccount\"}";
byte[] bytes = Encoding.UTF8.GetBytes(json);
httpWebRequest.ContentLength = bytes.Length;
using (Stream putStream = httpWebRequest.GetRequestStream())
{
putStream.Write(bytes, 0, bytes.Length);
}
HttpWebResponse httpWebResponse = null;
try
{
httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
}
catch (Exception e)
{
//return null;
var x = "Stop";
}
Thanks
400 response suggests that your API request payload is not correct.
You can try this call using IPP provided .net devkit.
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits/0150_ipp_.net_devkit_3.0/0002_synchronous_calls/0001_data_service_apis
Using Dev-defined lib( sample call ) -
https://gist.github.com/IntuitDeveloperRelations/0913b4c224de758fde0a
Thanks

Why is the HttpWebRequest body val null after "crossing the Rubicon"?

I am trying to send the contents of an XML file from a handheld device (Compact Framework/Windows CE) to a Web API method in my server app like so (Client code):
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
// test to see if it's finding any lines
//MessageBox.Show(line); <= works fine
sb.AppendLine(line);
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
if (timeout < 0)
{
request.ReadWriteTimeout = timeout;
request.Timeout = timeout;
}
request.ContentLength = postBytes.Length;
request.KeepAlive = false;
request.ContentType = "application/xml";
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
}
}
As you can see in the commented out code ("<= works fine"), I've tested it and the data I want is being added to the StringBuilder. There is no exception being thrown (I don't see "SendXMLFile exception ").
However, when the corresponding server code is called:
[Route("api/DeliveryItems/PostArgsAndXMLFileAsStr")]
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
string beginningInvoiceNum = string.Empty;
string endingInvoiceNum = string.Empty;
XDocument doc = XDocument.Parse(stringifiedXML);
...the "serialNum" and "siteNum" args are as expected (contain the valid expected values) but the body (stringifiedXML) is null. Why?
UPDATE
I added this, too, in the client:
request.ContentLength = postBytes.Length;
// Did the sb get into the byte array?
MessageBox.Show(request.ContentLength.ToString());
...and the byte array does have the data, as it shows me "112" (the XML file is quite small).
UPDATE 2
Now I added yet another debug msg:
try
{
Stream requestStream = request.GetRequestStream();
// now test this:
MessageBox.Show(string.Format("requestStream length is {0}", requestStream.Length.ToString()));
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
...and I don't even see the "requestStream length is" message; instead I see, "SendXMLFileException NotSupportedException"...???
UPDATE 3
I guess this is an example of the Hawthorn Effect or similar. Once I commented out that debug (MessageBox.Show()) statement, I'm back to making it into the server app, but with the [FromBody] val null.
Then the client has the message, "Unable to read data from the transport connection"
UPDATE 4
stringifiedXML is still null here:
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
string beginningInvoiceNum = string.Empty;
string endingInvoiceNum = string.Empty;
XDocument doc = XDocument.Parse(stringifiedXML);
...even after I modified the code in the client following a response to this question like so:
public static string SendXMLFile(string xmlFilepath, string uri)
{
MessageBox.Show(string.Format("In SendXMLFile() - xmlFilepath == {0}, uri == {1}", xmlFilepath, uri));
string strData = GetDataFromXMLFile();
HttpWebRequest request = CreateRequest(uri, HttpMethods.POST, strData, "application/xml");
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.GetResponseStream().ToString();
}
}
catch (Exception ex)
{
MessageBox.Show("SendXMLFile exception " + ex.Message);
request.Abort();
return string.Empty;
}
}
private static string GetDataFromXMLFile()
{
// test data - if it works, get the (same, for now) data from the file
return #"<?xml version=1.0?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"; //had to remove "s from version num
}
// Based on code from Andy Wiggly (the owner of Wiggly Field in Chicago and the Wiggly chewing gum company?)
public static HttpWebRequest CreateRequest(string uri, HttpMethods method, string data, string contentType)
{
WebRequest request = HttpWebRequest.Create(uri);
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
Encoding encoding = Encoding.UTF8;
request.ContentLength = encoding.GetByteCount(data);
request.ContentType = contentType;
request.GetRequestStream().Write(
encoding.GetBytes(data), 0, (int)request.ContentLength);
request.GetRequestStream().Close();
}
else
{
// If we're doing a GET or DELETE don't bother with this
request.ContentLength = 0;
}
// Finally, return the newly created request to the caller.
return request as HttpWebRequest;
}
Note: I don't know if this is just a misleading side-effect of shutting down the server, but I subsequently saw this err msg in the client/handheld app:
"System.Net.ProtocolVi..."
"This operation cannot be performed after the request has been submitted."
UPDATE 5
For those wanting a Stack Trace, &c:
serNum and siteNum are simple values that get concatenated into the uri like so:
string uri = string.Format("http://192.168.125.50:28642/api/FileTransfer/GetHHSetupUpdate?serialNum={0}&clientVersion={1}", serNum, clientVer);
I tried to get the Stack Trace like so:
catch (Exception ex)
{
MessageBox.Show(string.Format("Msg = {0}; StackTrace = {1)", ex.Message, ex.StackTrace));
request.Abort();
return string.Empty;
}
...but now I'm only seeing, "This operation cannot be performed after the request has been submitted."
UPDATE 6
I changed the method signature to this:
public static HttpWebResponse SendXMLFile(string xmlFilepath, string uri)
...and the corresponding code to this:
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
return response;
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("Msg = {0}; StackTrace = {1)", ex.Message, ex.StackTrace));
request.Abort();
return null;
}
...but it made no difference (and I see no "StackTrave = " message, so it must be failing erstwheres)
UPDATE 7
I put two debug strings in:
0)
public static HttpWebRequest CreateRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
//test:
MessageBox.Show(string.Format("In CreateRequestNoCredentials(); data passed in = {0}", data));
1) In SendXMLFile():
//test:
MessageBox.Show(string.Format("After calling CreateRequestNoCredentials(), request contentLen = {0}, headers = {1}, requestUri = {2}",
request.ContentLength, request.Headers, request.RequestUri));
...and I see this:
...but then before the second one gets a chance to show me the gory details, the server receives the null body value, crashes thuswith, and then the client whin[g]es with the same old "This operation cannot be performed after the request has been submitted" complaint.
UPDATE 8
In response to the suggestion, "I suspect that if you remove the setting of KeepAlive and ProtocolVersion after the CreateRequest call, the exception will go away.", I changed my code from this:
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, strData, "application/xml");
//test:
MessageBox.Show(string.Format("After calling CreateRequestNoCredentials(), request contentLen = {0}, headers = {1}, requestUri = {2}",
request.ContentLength, request.Headers, request.RequestUri));
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
public static HttpWebRequest CreateRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
//test:
MessageBox.Show(string.Format("In CreateRequestNoCredentials(); data passed in = {0}", data));
WebRequest request = HttpWebRequest.Create(uri);
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
Encoding encoding = Encoding.UTF8;
request.ContentLength = encoding.GetByteCount(data);
request.ContentType = contentType;
request.GetRequestStream().Write(
encoding.GetBytes(data), 0, (int)request.ContentLength);
request.GetRequestStream().Close();
}
else
{
// If we're doing a GET or DELETE don't bother with this
request.ContentLength = 0;
}
// Finally, return the newly created request to the caller.
return request as HttpWebRequest;
}
...to this:
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, strData, "application/xml");
//test:
MessageBox.Show(string.Format("After calling CreateRequestNoCredentials(), request contentLen = {0}, headers = {1}, requestUri = {2}",
request.ContentLength, request.Headers, request.RequestUri));
public static HttpWebRequest CreateRequestNoCredentials(string uri, HttpMethods method, string data, string contentType)
{
//test:
MessageBox.Show(string.Format("In CreateRequestNoCredentials(); data passed in = {0}", data));
WebRequest request = HttpWebRequest.Create(uri);
request.Method = Enum.ToObject(typeof(HttpMethods), method).ToString();
request.ContentType = contentType;
((HttpWebRequest)request).Accept = contentType;
// moved from elsewhere to here:
((HttpWebRequest)request).KeepAlive = false;
((HttpWebRequest)request).ProtocolVersion = HttpVersion.Version10;
if (method != HttpMethods.GET && method != HttpMethods.DELETE)
{
Encoding encoding = Encoding.UTF8;
request.ContentLength = encoding.GetByteCount(data);
request.ContentType = contentType;
request.GetRequestStream().Write(
encoding.GetBytes(data), 0, (int)request.ContentLength);
request.GetRequestStream().Close();
}
else
{
// If we're doing a GET or DELETE don't bother with this
request.ContentLength = 0;
}
// Finally, return the newly created request to the caller.
return request as HttpWebRequest;
}
...and yet I still get that same err msg ("This operation cannot be performed after the request has been submitted") and stringifiedXML is still null when it hits the server.
UPDATE 9
Here is what I get when I send what I understand to be what I should via Fiddler 2 (right-click the image and open in a new tab if you don't have visual superpowers):
...but I don't know what I'm looking at...did it work? Did it fail? The "body == 0" column gives me pause/makes me think it failed, yet "204" seems to mean "The server successfully processed the request, but is not returning any content"...
UPDATE 10
Here is the Fiddler scream shot after fixing the uri, and I do reach the breakpoint in the server app, with good data sent:
UPDATE 11
With changing this code:
string strData = sb.ToString();
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, strData, "application/xml");
...to this:
string strData = #sb.ToString(); // GetDataFromXMLFile();
string body = String.Format("\"{0}\"", strData);
HttpWebRequest request = CreateRequestNoCredentials(uri, HttpMethods.POST, body, "application/json");
...I'm now getting this in stringifiedXML: "
...and so I'm now getting: "System.Xml.XmlException was unhandled by user code
HResult=-2146232000
Message=Unexpected end of file has occurred. Line 1, position 15..."
It's an improvement, anyway...
UPDATE 12
Depending on the exact makeup/formatting of the string passed as "Request Body" in Fiddle, the results differ radically.
With this as Request Body:
<?xml version="1.0"?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>
...stringifiedXML is null
With this as Request Body:
"<?xml version=1.0?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
...stringifiedXML is exactly the same ("")
...but there is an exception:
System.Xml.XmlException was unhandled by user code
HResult=-2146232000
Message='1.0' is an unexpected token. The expected token is '"' or '''. Line 1, position 15.
Source=System.Xml
LineNumber=1
LinePosition=15
SourceUri=""
StackTrace:
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
at System.Xml.XmlTextReaderImpl.ThrowUnexpectedToken(String expectedToken1, String expectedToken2)
at System.Xml.XmlTextReaderImpl.ParseXmlDeclaration(Boolean isTextDecl)
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
at System.Xml.Linq.XDocument.Parse(String text, LoadOptions options)
at System.Xml.Linq.XDocument.Parse(String text)
at HandheldServer.Controllers.DeliveryItemsController.d__2.MoveNext() in c:\HandheldServer\HandheldServer
\Controllers\DeliveryItemsController.cs:line 63
InnerException:
With this as Request Body:
"<?xml version="1.0"?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
...stringifiedXML is "
Penultimately, with this as Request Body:
"<?xml version=\"1.0\"?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
...stringifiedXML is exactly the same thing ("")
...but I get this exception:
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Sequence contains no elements
Source=System.Core
StackTrace:
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at HandheldServer.Controllers.DeliveryItemsController.d__2.MoveNext() in c:\HandheldServer\HandheldServer\Controllers\DeliveryItemsController.cs:line 109
InnerException:
And finally, if I pass this, with (albeit bogus) vals within the angulars:
"<?xml version=\"1.0\"?><LocateAndLaunch><Tasks>Some Task</Tasks><Locations>Some Location</Locations></LocateAndLaunch>"
...I STILL get "sequence contains no elements"
This method is more picky than Rachel Canning! What does it want - egg in its beer?!?
UPDATE 13
With this code:
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
XDocument doc = XDocument.Parse(await Request.Content.ReadAsStringAsync());
...or this:
. . .XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
...and this as the incoming stringifiedXML:
"Some TaskSome Location"
...I get the exception:
"System.Xml.XmlException was unhandled by user code
HResult=-2146232000
Message=Root element is missing."
With this code (same stringifiedXML):
XDocument doc = XDocument.Parse(stringifiedXML);
... I get, "System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Sequence contains no elements
Source=System.Core
StackTrace:
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at HandheldServer.Controllers.DeliveryItemsController.d__2.MoveNext() in c:\HandheldServer\HandheldServer
\Controllers\DeliveryItemsController.cs:line 109
InnerException: "
IOW, depending on how I parse the incoming string, I get either "Root element is missing" or "Sequence contains no elements"
What the Deuce McAlistair MacLean Virginia Weeper?!? Isn't "<LocateAndLaunch>" a root element? Aren't "Some Task" and "Some Location" elements?
For the action method like this
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML,
string serialNum, string siteNum)
{}
the request message must be like this. I use JSON here.
POST http://localhost:port/api/values/PostArgsAndXMLFileAsStr?serialNum=1&siteNum=2 HTTP/1.1
Content-Type: application/json
Host: localhost:port
Content-Length: 94
"<?xml version=1.0?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>"
The request body needs to contain the double quotes, BTW. With this, binding should work correctly.
So, post the message with content type application/json and format the body like this.
string content = #"<?xml version=1.0?><LocateAndLaunch><Tasks></Tasks><Locations></Locations></LocateAndLaunch>";
string body = String.Format("\"{0}\"", content);
Before, you change anything in the client side code, use Fiddler to send a POST like the one above to ensure it works in the web API side. After that, change your client side to make sure it outputs the request just the working request with Fiddler.

Sending multiple parameters to POST method in .net:

I'm struggling to use POST method for RESTful services. My requirement is some parameters I need to append (not in the URL) and 2 parameters I need to read from file. The service is written in Java.
string url= "http://srfmdpimd2:18109/1010-SF-TNTIN/Configurator/rest/importConfiguration/"
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
FileStream file = new FileStream(#"TestSCDS.properties", FileMode.Open);
Byte[] bytes = new Byte[file.Length];
file.Read(bytes, 0, bytes.Length);
string strresponse = Encoding.UTF8.GetString(bytes);
request.Method = "POST";
request.ContentType = "multipart/form-data;";
request.ContentLength = file.Length;
request.Headers.Add("hhrr", "H010");
request.Headers.Add("env", "TEST");
request.Headers.Add("buildLabel", "TNTAL_05.05.0500_C54");
Stream Postdata = request.GetRequestStream();
Postdata.Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();`
request.Headers.Add() is adding parameters to URL? If not, how can I send multiple parameters to POST method in restful services?
Also, how to read parameters from file and make use in POST method?
It needs a little leg work, encode a dictionary and put it in the body. Below is a quick sample:
private string Send(string url)
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
string postData = EncodeDictionary(args, false);
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] postDataBytes = encoding.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postDataBytes.Length;
using(Stream requestStream = request.GetRequestStream())
{
requestStream.Write(postDataBytes, 0, postDataBytes.Length);
}
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
}
private string EncodeDictionary(Dictionary<string, string> dict,
bool questionMark)
{
StringBuilder sb = new StringBuilder();
if (questionMark)
{
sb.Append("?");
}
foreach (KeyValuePair<string, string> kvp in dict)
{
sb.Append(HttpUtility.UrlEncode(kvp.Key));
sb.Append("=");
sb.Append(HttpUtility.UrlEncode(kvp.Value));
sb.Append("&");
}
sb.Remove(sb.Length - 1, 1); // Remove trailing &
return sb.ToString();
}
I don't know what your complete requirements are, but my strong suggestion is to "start simple".
Do not use "Content-type: multipart/form-data" unless you're sure you need it. Instead, start out with "application/x-www-form-urlencoded" (an old favorite) or "application/json" (even better).
Here is a nice little step-by-step example. You can find literally 100's more with a simple Google search:
http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client