I’ve got 2 projects that run on different servers but both have a reference to a common dll that contains a complex type called LeadVM. LeadVM contains sub-objects, like Employer which contains properties. Ex:
LeadVM.FirstName
LeadVM.LastName
LeadVM.Employer.Name
LeadVM.Employer.Phone
So, project 1 can create a LeadVM type of object, and populate it. I need to then, via an HTTP call, POST in the data to a controller/action in the 2nd project. The 2nd project knows what a LeadVM object is.
How can I...serialize(?) LeadVM and pass it to the accepting Action in the 2nd project?
EDIT: Thanks to #Unicorno Marley, I ended up using the Newtonsoft JSON stuff.
Now I just create my object in project 1, then do the following code (I'm sure it's clunky but it works).
LeadVM NewCustomer = new LeadVM();
NewCustomer.set stuff here....
var js = Newtonsoft.Json.JsonSerializer.Create();
var tx = new StringWriter();
js.Serialize(tx, NewCustomer);
string leadJSON = tx.ToString();
And then I can use HttpWebRequest to send a web request to my project 2.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:1234/Lead/Create");
request.Method = "POST";
StreamWriter streamOut = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
streamOut.Write(System.Web.HttpUtility.UrlEncode(leadJSON));
streamOut.Close();
HttpWebResponse resp = null;
resp = (HttpWebResponse)request.GetResponse();
StreamReader responseReader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8);
sResponse = responseReader.ReadToEnd();
resp.Close();
In project 2, I can catch the json sent like this and my NewCustomer object in project 2 is already populated, ready for use.
var buffer = new byte[Request.InputStream.Length];
Request.InputStream.Read(buffer, 0, buffer.Length);
string json = System.Text.Encoding.Default.GetString(buffer);
json = System.Web.HttpUtility.UrlDecode(json);
LeadVM NewCustomer = Newtonsoft.Json.JsonConvert.DeserializeObject<PhoenixLead.LeadVM>(json);
I'm sure I'm doing things very awkwardly. I'll clean it up, but wanted to post the answer that I was led to.
Json is probably the most common option, there is a good json library for c# that can be found here:
http://james.newtonking.com/json
Alternatively, since youre just doing an HTTP post and you only have one object, the fastest option would just be to write out the data line by line and have the recipient machine parse it. Since they both know what a LeadVM is, and both presumably have the same definition, it would be trivial to read a text string into the proper variables. This quickly becomes the slower option if you decide to add more object types to this process though.
Related
How can I call HTTP GET using JSON parameters in content body?
I tried this:
HttpWebRequest.WebRequest.Create(_uri);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
httpWebRequest.Headers.Add("X-AUTH-TOKEN", _apiKey);
using(var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) {
string _json = "\"{\"filter\": {\"relation\": \"equals\", \"attribute\": \"state\", \"value\": \"CA\" }, \"insights\": {\"field\": \"family.behaviors\", \"calculations\": [\"fill_count\"]}}";
streamWriter.Write(_json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse) httpWebRequest.GetResponse();
using(var streamReader = new StreamReader(httpResponse.GetResponseStream())) {
var result = streamReader.ReadToEnd();
}
but it throws an exception:
"Cannot send a content-body with this verb-type."
If you use .NET core, the new HttpClient can handle this. Otherwise you can use System.Net.Http.WinHttpHandler package, but it has a ton of dependencies. See answer
https://stackoverflow.com/a/47902348/1030010
for how to use these two.
I can't use .NET core and I don't want to install System.Net.Http.WinHttpHandler.
I solved it by using reflection, to trick WebRequest that it is legal to send body with a GET request (which is according to latest RFC). What I do is to set ContentBodyNotAllowed to false for HTTP verb "GET".
var request = WebRequest.Create(requestUri);
request.ContentType = "application/json";
request.Method = "GET";
var type = request.GetType();
var currentMethod = type.GetProperty("CurrentMethod", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(request);
var methodType = currentMethod.GetType();
methodType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(currentMethod, false);
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write("<Json string here>");
}
var response = (HttpWebResponse)request.GetResponse();
Note, however, that the attribute ContentBodyNotAllowed belongs to a static field, so when its value changes, it remains in effect for the rest of the program. That's not a problem for my purposes.
It is entirely possible, but you have to use the newer HttpClient class: https://stackoverflow.com/a/47902348/70345
Even tho it is technically allowed to send a body with Get requests, Microsoft has decided for you that you cannot do that.
This can be seen in HttpWebRequest source code:
if (onRequestStream) {
// prevent someone from getting a request stream, if the protocol verb/method doesn't support it
throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget));
}
So you need to change your verb to Put or Post or have some other workaround.
GET will only receive it.
If you need to specify parameters, please include it in url.
Or you can send JSON BODY if POST or PUT.
HTTP request methods
HTTP defines a set of request methods to indicate the desired action to be performed for a given resource. Although they can also be nouns, these request methods are sometimes referred as HTTP verbs. Each of them implements a different semantic, but some common features are shared by a group of them: e.g. a request method can be safe, idempotent, or cacheable.
GET
The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
HEAD
The HEAD method asks for a response identical to that of a GET request, but without the response body.
POST
The POST method is used to submit an entity to the specified resource, often causing a change in state or side effects on the server.
PUT
The PUT method replaces all current representations of the target resource with the request payload.
In Addition:
I found this. Long discussion has been held.
HTTP GET with request body
What this means is that it is possible to send BODY with GET, but sending a payload body on a GET request might cause some existing implementations to reject the request (such as Proxy in the middle of the route).
Please be sure to read this article carefully as there are many other points to pay attention to.
By the way, it seems that you can send GET with body using the -i option of cURL command.
Curl GET request with json parameter
I am going through the example exam questions for Microsoft exam 70-483 "Programming in C#".
There is one question the answer to which I don't understand and couldn't find anything about the topic on the Internet.
The question is:
You are implementing a method named ProcessFile that retrieves data files from web servers and FTP servers. The ProcessFile() method has the following method signature:
Public void ProcessFile(Guid dataField, string dataFileUri)
Each time the ProcessFile() method is called, it must retrieve a unique data file and then save the data file to disk.
You need to complete the implementation of the
ProcessFile() method. Which code segment should you use?
FileWebRequest request = FileWebRequest.Create(dataFileUri) as FileWebRequest;
using (FileWebResponse response = request.GetResponse() as FileWebResponse)
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
using (StreamWriter writer = new StreamWriter(dataFieldId + ".dat"))
{
writer.Write(reader.ReadToEnd());
}
-or-
WebRequest request = WebRequest.Create(dataFileUri);
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
using (StreamWriter writer = new StreamWriter(dataFieldId + ".dat"))
{
writer.Write(reader.ReadToEnd());
}
According to the question-making people, the latter snippet, using "WebRequest" is the correct one. But I cannot figure out why the "FileWebRequest" one isn't.
Keep in mind the questions I am doing have been wrong a lot in the past, so maybe this isn't correct, either?
Some hours ago I also have met this question. Early I have not work with this, but by searching info in Google I concluded followings:
the main words in question is from web servers and FTP servers,
that means that dataFileUri may be like http://mywebserver or ftp://myftpserver
when you try to get file from ftp server, for example:
//from answer
var request1 = WebRequest.Create("ftp://myftpserver");
//from answer
var request2 = FileWebRequest.Create("ftp://myftpserver") as FileWebRequest;
var request3 = WebRequest.Create("ftp://myftpserver") as FtpWebRequest;
request1, request3 will have request value with type SystemNet.FtpWebRequest. request2 will be null.
The similar behavior will be when you try to use http://mywebserver: request2, request3 will be null.
when you use WebRequest the type of the request will be automatically detected by transfer protocol
So you don't need to think about whether file stored on web server/file server/ftp server
I have no problem deserializing an xml into my class while using the following code. I was wondering if it was possible to use the same code on a local file, as our source files are saved locally for archival purposes and are occasionally reprocessed.
This works for remote xml but not for local xml:
RestRequest request = new RestRequest();
var client = new RestClient();
//doesnt work
client.BaseUrl = directory;
request.Resource = file;
//works
client.BaseUrl = baseURL;
request.Resource = url2;
IRestResponse<T> response = client.Execute<T>(request);
return response.Data;
Is there a way to use RestSharp from a local file? I was going to try to use the same function regardless of whether the xml is local or remote and just pass it the location of the xml to read.
This is in fact possible using built in JsonDeserializer class as below. I have used this method to stub API response for testing.
// Read the file
string fileContents = string.Empty;
using (System.IO.StreamReader reader = new System.IO.StreamReader(#"C:\Path_to_File.txt"))
{
fileContents = rd.ReadToEnd();
}
// Deserialize
RestResponse<T> restResponse = new RestResponse<T>();
restResponse.Content = fileContents;
RestSharp.Deserializers.JsonDeserializer deserializer = new RestSharp.Deserializers.JsonDeserializer();
T deserializedObject = deserializer.Deserialize<T>(restResponse);
This is not possible with standard functionality. For example "file://" URLs do not work with RestSharp.
I would recommend using RestSharp do get the returned data from a Uri and having another function to deserialize this data into an object.
You can use the same funcion then to deserialize from file data.
RestSharp is a library to do REST calls, not to deserialize from arbitrary sources. Even if there is a possibility to make RestSharp believe it is talking to a website instead of a file, it would be a hack.
If you need it you could still use the XmlDeserializer from RestSharp. It expects a IRestResponse object, but it only uses the Content property from it, so it should be easy to create. It still feels like a hack though and there are more than enough other XmlSerializers out there that will do a great job
I have been playing with ASP.NET Web API. I am looking to see can I post to a method I have built which simply returns back the object I have POSTED:
On The Accounts Controller:
// POST /api/accounts
public Account Post(Account account)
{
return account;
}
Code Used To Post:
public void PostAccount()
{
// http://local_ip/api/accounts
var uri = string.Format("{0}", webServiceRoot);
var acc = new Account();
acc.AccountID = "8";
acc.AccountName = "Mitchel Cars";
acc.AccountNumber = "600123801";
acc.SubscriptionKey = "2535-8254-8568-1192";
acc.ValidUntil = DateTime.Now;
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/xml";
request.ContentLength = 800;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Account));
xmlSerializer.Serialize(request.GetRequestStream(), acc);
var response = (HttpWebResponse)request.GetResponse();
XmlSerializer serializer = new XmlSerializer(typeof(Account));
var newAcc = (Account)serializer.Deserialize(response.GetResponseStream());
}
I have removed any error checking or any boiler plate code to make it easier to read. This is strictly a spike just to under stand to to actually POST. My understanding is that you should write to the GetRequestStream(). All the reading and such seems to work ok but I never here back from the request.GetResponse();
If I do a simple get it works fine. I did see you can use a class called HTTPClient for doing this stuff but I can't use it as I need to get this working for WinForms, Silverlight and Windows Phone all based on .Net 3.5
Any help pushing POCO's to the server would be a great help, cheers!
ADDITIONAL INFO:
Currently I get no error, the test app just hangs.
If I turn off the WebAPI project I get a server not found response.
I have not changed any routes or any of that.
Gets to the same controller work.
You will need to close the response stream. Most examples I see also show setting the content length. You may be better to serialize to a memory stream and then use the length of that stream as the Content-Length. Unfortunately in .net 3.5 there is no CopyStream so you may have to write that yourself.
If you want to use the HttpClient, you can install the download the REST starter Kit. and use the DLLs as external DLLs
http://forums.asp.net/t/1680252.aspx/1
In a project I'm invovled in, there is a requirment that the price of certain
stocks will be queryed from some web interface and be displayed in some way.
I know the "query" part of the requirment can be easily implemented using a Perl module like LWP::UserAgent. But for some reason, C# has been chosen as the language to implement the Display part. I don't want to add any IPC (like socket, or indirectly by database) into this tiny project, so my question is there any C# equivalent to the Perl's LWP::UserAgent?
You can use the System.Net.HttpWebRequest object.
It looks something like this:
// Setup the HTTP request.
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create("http://www.google.com");
// This is optional, I'm just demoing this because of the comments receaved.
httpWebRequest.UserAgent = "My Web Crawler";
// Send the HTTP request and get the response.
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
if (httpWebResponse.StatusCode == HttpStatusCode.OK)
{
// Get the HTML from the httpWebResponse...
Stream responseStream = httpWebResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string html = reader.ReadToEnd();
}
I'm not sure, but are you simply trying to make an HTTP Request? If so, you can use the HttpWebRequest class. Here's an example http://www.csharp-station.com/HowTo/HttpWebFetch.aspx
If you want to simply fetch data from the web, you could use the WebClient class. It seems to be quite good for quick requests.