How to convert Object and view it on WebAPI? - c#

Here is my question,
I got a Web API and client(winform), client will send out data with a Serialize Object. My Web API do have received and return a response to client. But I can't view the data on Web API, I do have try using Deserialize Object and convert it into string but not working neither.
Please help me,Thanks!
Here is my code:
Client
private string WebApiPost(string sParam, string sJson)
{
var client = new HttpClient();
var content = new StringContent(sJson, Encoding.UTF8, "application/json");
var response = client.PostAsync(sWebAPI_URL + sParam, content).Result;
var body = response.Content.ReadAsStringAsync().Result;
return body;
}
This is my Web API
public object Post([FromBody]object hL7)
{
//what should I do???
//I've tried set hL7 into string but it wont get any data;
//I've also tried deserialize it but will get 500 internal server error.
return hL7;
}
This is my WebAPI model
public class HL7MID
{
public string LOC { get; set; }
public string COMPANY { get; set; }
}
public class HL7MID_List
{
public string sMSG { get; set; }
public List<HL7MID> data = new List<HL7MID>();
}

Because sJson matches HL7MID, you can use that type in as a paramter of your Post function, and just use that type.
public HL7MID Post([FromBody]HL7MID hL7)
{
//use hL7 here
return hL7;//also since you know the return type, changing that to HL7MID is suggested
}

Related

C# .NET Core 3.1 Web API Post parameter is Null

I am trying to make a post request from WPF to Web API using the following code but the request parameter is always null.
Request Model
public class Document
{
public string FileName { get; set; }
public byte[] Buffer { get; set; }
}
public class Request
{
public string Uploader { get; set; }
public List<Document> Documents { get; set; }
}
WPF Client
var obj = new Request()
{
Uploader = "John Doe",
Documents = new List<Document>
{
new Document()
{
FileName ="I Love Coding.pdf",
Buffer = System.IO.File.ReadAllBytes(#"C:\Users\john.doe\Downloads\I Love Coding.pdf.pdf")
}
}
};
using (var http = new HttpClient())
{
var encodedJson = JsonConvert.SerializeObject(obj);
var conent = new StringContent(encodedJson, Encoding.UTF8, "application/json");
HttpResponseMessage response = await http.PostAsync("https://my-app.com/api/upload", conent);
response.EnsureSuccessStatusCode();
}
Web API
[Route("")]
public class AppController : ControllerBase
{
[HttpPost]
[Route("api/upload")]
public async Task<IActionResult> UploadDocumentsAsync([FromBody] Request request)
{
// request is always null when app is running in production
// https://my-app.com/api/upload
//request is not null when running on https://localhost:8080/api/upload
}
}
Please what am I missing in the above implementation?
The request parameter is not null on localhost but always null in production.
Please what am I missing in the above implementation? The request
parameter is not null on localhost but always null in production.
Well, not sure how are getting data on local server becuse, you are sending MultipartFormData means your POCO object and file buffer. As you may know we can send json object in FromBody but not the files as json. Thus, I am not sure how it working in local and getting null data is logical in IIS Or Azure.
what am I missing in the above implementation?
As explained above, for sending both POCO object and Files as byte or steam we need to use FromForm and beside that, we need to bind our request object as MultipartFormDataContent to resolve your null data on your UploadDocumentsAsync API action.
Required Change For Solution:
WPF:
In your WPF http request please update your request code snippet as following:
var obj = new Request()
{
Uploader = "John Doe",
Documents = new List<Document>
{
new Document()
{
FileName ="I Love Coding.pdf",
Buffer = System.IO.File.ReadAllBytes(#"YourFilePath")
}
}
};
var httpClient = new HttpClient
{
BaseAddress = new("https://YourServerURL")
};
var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent(obj.Uploader), "Uploader");
formContent.Add(new StringContent(obj.Documents[0].FileName), "Documents[0].FileName");
formContent.Add(new StreamContent(new MemoryStream(obj.Documents[0].Buffer)), "Documents[0].Buffer", obj.Documents[0].FileName);
var response = await httpClient.PostAsync("/api/upload", formContent);
if (response.IsSuccessStatusCode)
{
var responseFromAzureIIS = await response.Content.ReadAsStringAsync();
}
Note: Class in WPF side would remain same as before. No changes required.
Asp.net Core Web API:
In asp.net core web API side you should use [FromForm] instead of [FromBody]
So your controller Action would as following:
[Route("")]
public class AppController : ControllerBase
{
[HttpPost]
[Route("api/upload")]
public async Task<IActionResult> UploadDocumentsAsync([FromForm] Request file)
{
if (file.Documents[0].Buffer == null)
{
return Ok("Null File");
}
return Ok("File Received");
}
}
Note: For remote debugging I have checked the logs and for double check I have used a simple conditionals whether file.Documents[0].Buffer == null. I have tested both in local, IIS and Azure and working accordingly.
Update POCO Class in API Project:
For buffer you have used byte for your WPF project but for Web API project update that to IFormFile instead of byte. It should be as following:
public class Document
{
public string FileName { get; set; }
public IFormFile Buffer { get; set; }
}
public class Request
{
public string Uploader { get; set; }
public List<Document> Documents { get; set; }
}
Output:
If you would like to know more details on it you could check our official document here

DateTime property value is not correctly received in Asp.Net Core WebApi Controller

I am using Asp.Net Core 2.2 WebApi and WinForm Client for sending requests. I am using RestSharp library as Restclient. It seems Property values with DateTime type is not correctly handled in WebApi Controller.
Source DateTime:
Target DateTime:
Client side code:
internal virtual void Add(T1 businessObject)
{
RestRequest request = new RestRequest(ManagementControllerName + #"/" + AddActionPrefix, Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(businessObject);
var response = Globals.ServiceStackClient.Execute(request);
if (!response.IsSuccessful)
{
var ex = JsonConvert.DeserializeObject<AppExceptionMessage>(response.Content);
throw new ClientSideException(ex);
};
}
Business object:
public class DmPresentationBo : CatalogBo
{
public DmPresentationBo()
{
}
public string DocItemNumber { get; set; }
public DateTime DocItemDt { get; set; }
}
WebApi Controller:
[HttpPost]
[Route("Add")]
public ActionResult<T1> Add([FromBody] T1 businessObject)
{
try
{
CurrentDbStorage.StartTransaction();
var mainCmd = CurrentDbStorage.GenerateCrudInsertCommand(businessObject);
mainCmd.ExecuteNonQuery();
ProcessPostAdd(businessObject);
CurrentDbStorage.CommitTransaction();
}
catch (Exception ex)
{
CurrentDbStorage.RollbackTransaction();
var parsedEx = CurrentExceptionMgr.ParseErrorMsg(ex.Message);
return new BadRequestObjectResult(parsedEx);
};
return Ok(businessObject);
}
Setting Breakpoint within controller, it showed me that BusinessObject deserialized incorrectly, like DocItemDt property value is less than actual one which sent by Client. Surfing google, there are some problems with Json DateTime handling, however none of them helped me.
Thanks for your help.

Retrieving the response from Rest API

I am working on creating an API that call the other third party API. The third party API is an REST API and returns response in the JSON format when I call it in the web browser
[{"Acc":"IT","Cnt":"023","Year":"16"}]
I am trying to get the same response when I call the third party API from my API.
public IHttpActionResult Get(string acctID)
{
using (var client_EndPoint= new HttpClient())
{
Uri uri_EndPoint = new Uri(BaseURL_EndPoint);
client_EndPoint.BaseAddress = uri;
client_EndPoint.DefaultRequestHeaders.Accept.Clear();
client_EndPoint.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string EndPoint_URL = BaseURL_EndPoint+"api/NameCreation?Account="+acctID;
var response_EndPoint = client_EndPoint.GetAsync(EndPoint_URL).Result;
string responseString = response_EndPoint.Content.ReadAsStringAsync().Result;
return Ok(responseString);
}
}
What I have been doing is getting the response from the third party API in a string. But I am checking if there is a way I can get in the JSON format so I can return them directly. The return type of the get method is IHttpActionResult. If I am returning as string the response looks like
"[{\"Acc\":\"adm\",\"Cnt\":\"001\",\"Year\":\"16\"}]"
Any help is greatly appreciated.
Create a model to hold rest api data
public class Model {
public string Acc { get; set; }
public string Cnt { get; set; }
public string Year { get; set; }
}
Deserialize it from api
var response_EndPoint = await client_EndPoint.GetAsync(EndPoint_URL);
var models = await response_EndPoint.Content.ReadAsAsync<Model[]>();
And then return that
return Ok(models);
Full example
public async Task<IHttpActionResult> Get(string LabName) {
using (var client_EndPoint = new HttpClient()) {
//...other code removed for brevity
var response_EndPoint = await client_EndPoint.GetAsync(EndPoint_URL);
var models = await response_EndPoint.Content.ReadAsAsync<Model[]>();
return Ok(models);
}
}
you can use Newtonsoft.Json ,Just add it from nuget and add this config to webapiconfig:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
then use
return Json(responseString)

web api receive object with null variables

I have webforms asp and web api. In web forms I try send to web api object of class this way:
HttpClient client = HttpClientHeader("", login, ClassMd5Calc.CalculateMd5Hash(password));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
UserTariff userTariff = new UserTariff();
userTariff.Login = "some value";
userTariff.Password = "some value";
userTariff.TariffName = "some value";
var json = new JavaScriptSerializer().Serialize(userTariff);
StringContent content = new StringContent(json);
content.Headers.ContentType = new MediaTypeHeaderValue("text/json");
HttpResponseMessage response = client.PostAsync("api/ChangeTariff/", content).Result;
This is my class (exist in data contract solution, so both project are use this class).
[Serializable]
public class UserTariff
{
public String Login { get; set; }
public String Password { get; set; }
public String TariffName { get; set; }
public decimal Balance { get; set; }
}
My web api receive package, but all field are null. What's wrong? How it's fix?
public class ChangeTariffController : ApiController
{
public void Post([FromBody] UserTariff mes)
{
//mes exist, but his property are null: mes.Login=null; mes.Password=null and e.t.c. but need value: "some value"
UPDATE 1.
I also tryed this code, but it show same error:
var content = new ObjectContent<UserTariff>(new UserTariff(), new JsonMediaTypeFormatter());
content.Headers.ContentType = new MediaTypeHeaderValue("text/json");
HttpResponseMessage response = client.PostAsync("api/ChangeTariff/", content).Result;
You can set the object content instead of the string content and should be using json media type formatter. This should fix the null bound variable in web api.
Also, use the newton soft json lib to convert the object to json.

How do I post data to MVC Controller using HttpWebRequest?

I am trying to post data to MVC controller action but have been unsuccessful so far.
Here is the structure of the post data:
private string makeHttpPostString(XmlDocument interchangeFile)
{
string postDataString = "uid={0}&localization={1}&label={2}&interchangeDocument={3}";
InterchangeDocument interchangeDocument = new InterchangeDocument(interchangeFile);
using (var stringWriter = new StringWriter())
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
interchangeFile.WriteTo(xmlTextWriter);
string interchangeXml = HttpUtility.UrlEncode(stringWriter.GetStringBuilder().ToString());
string hwid = interchangeDocument.DocumentKey.Hwid;
string localization = interchangeDocument.DocumentKey.Localization.ToString();
string label = ConfigurationManager.AppSettings["PreviewLabel"];
return (string.Format(postDataString, hwid, localization, label, interchangeXml));
}
}
Here is the request:
HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(controllerUrl);
webRequest.Method = "POST";
// webRequest.ContentType = "application/x-www-form-urlencoded";
string postData = makeHttpPostString(interchangeFile);
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
webRequest.ContentLength = byteArray.Length;
using (Stream dataStream = webRequest.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
}
HttpWebResponse webresponse = (HttpWebResponse) webRequest.GetResponse();
When I set the contenttype of the request to "application/x-www-form-urlencoded" GetReponse() fails with server error code 500. When I comment that out and only httpencode the xml data, "interchangeXml", the post is sent but only the 3rd parameter, "label" reaches the controller. The others are null.
What is the correct way to post values to a controller action when one of those values is xml data?
Thanks!
Update
I am send all the parameter with the exception of the XML via the query string. However, the problem now is that I do not know how to access the posted data in the controller action. Can someone tell me how I access the xml from the HttpRequest from with my Controller Action?
Update
I have refactored the above code to use the suggests made to me by Darin. I am recieveing an internal server error (500) using the WebClient UploadValues().
Action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult BuildPreview(PreviewViewModel model)
{
...
}
Request:
private string PostToSxController(XmlDocument interchangeFile, string controllerUrl)
{
var xmlInterchange = new InterchangeDocument(interchangeFile);
using (var client = new WebClient())
{
var values = new NameValueCollection()
{
{"uid", xmlInterchange.DocumentKey.Hwid},
{"localization", xmlInterchange.DocumentKey.Localization.ToString()},
{"label", ConfigurationManager.AppSettings["PreviewLabel"]},
{"interchangeDocument", interchangeFile.OuterXml }
};
byte[] result = null;
try
{
result = client.UploadValues(controllerUrl, values);
}
catch(WebException ex)
{
var errorResponse = ex.Response;
var errorMessage = ex.Message;
}
Encoding encoding = Encoding.UTF8;
return encoding.GetString(result);
}
}
Route:
routes.MapRoute(
"BuildPreview",
"SymptomTopics/BuildPreview/{model}",
new { controller = "SymptomTopics", action = "BuildPreview", model = UrlParameter.Optional }
);
Too complicated and unsafe your client code with all those requests and responses. You are not encoding any of your request parameters, not to mention this XML which is probably gonna break everything if you don't encode it properly.
For this reason I would simplify and leave the plumbing code about encoding, etc... to the .NET framework:
using (var client = new WebClient())
{
var values = new NameValueCollection
{
{ "uid", hwid },
{ "localization", localization },
{ "label", label },
{ "interchangeDocument", interchangeFile.OuterXml },
};
var result = client.UploadValues(controllerUrl, values);
// TODO: do something with the results returned by the controller action
}
As far as the server side is concerned, as every properly architected ASP.NET MVC application, it would obviously use a view model:
public class MyViewModel
{
public string Uid { get; set; }
public string Localization { get; set; }
public string Label { get; set; }
public string InterchangeDocument { get; set; }
}
with:
[HttpPost]
public ActionResult Foo(MyViewModel model)
{
// TODO: do something with the values here
...
}
Obviously this could be taken a step further by writing a view model reflecting the structure of your XML document:
public class Foo
{
public string Bar { get; set; }
public string Baz { get; set; }
}
and then your view model will become:
public class MyViewModel
{
public string Uid { get; set; }
public string Localization { get; set; }
public string Label { get; set; }
public Foo InterchangeDocument { get; set; }
}
and the last part would be to write a custom model binder for the Foo type that will use a XML serializer (or whatever) to deserialize back the InterchangeDocument POSTed value into a Foo instance. Now that's serious business.
I'm wrestling the same beast over here: Trying to set up a controller action as Xml endpoint
You may be getting the internal server error because either you have page validation on (solution: addotate with ValidateInput(false)), or you're not sending an Accept-Encoding header with your request. I would very much like to hear how I can get MVC to accept posted input without the Accept-Encoding HTTP header...
I just found that you can call a controller, even a dependency injected one, even from a Web Forms code behind using the "T4MVC" Nuget package:
https://github.com/T4MVC/T4MVC

Categories