I'm quite new to MVC and Web API.
I'm trying to post a MailMessage(System.Net.Mail) object to the web api that I've created but the object is received as empty at API. I'm using ReshSharp to call the api below is my code:
MailMessage myMail = new System.Net.Mail.MailMessage("from#example.com", "to#example.com");
myMail.Subject = "Test message from client";
myMail.SubjectEncoding = System.Text.Encoding.UTF8;
myMail.Body = "<b>Test Mail</b><br>using <b>HTML from client</b>.";
myMail.BodyEncoding = System.Text.Encoding.UTF8;
myMail.IsBodyHtml = true;
RestClient client = new RestClient("http://localhost:53014/api/email");
var request = new RestRequest("SendMailMessage", Method.POST);
var json = request.JsonSerializer.Serialize(myMail);
request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
request.RequestFormat = DataFormat.Json;
var res = client.Execute(request);
This is my API method:
[HttpPost]
public void SendMailMessage([FromBody]MailMessage myEmail)
{
//Code to send email
}
This is what I receive at the API end:
I have also tried this way but same output:
request = new RestRequest("SendMailMessage", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(myMail);
res = client.Execute(request);
I have also tried the Newtonsoft.Json serializer to serialize object but no success
var json = JsonConvert.SerializeObject(myMail);
Can anyone suggest what am I missing here?
Trying to send a MailMessage is problematic.
You should create a custom object to hold the information you want sent to the web API...
public class Email {
public string Body { get; set; }
public bool IsBodyHtml { get; set; }
public string Subject { get; set; }
public string[] To { get; set; }
//...Any other properties you deem relevant
//eg: public string From { get; set; }
}
Keep it simple.
So now you would send the custom object to the web api
var myMail = new Email() {
To = new [] { "to#example.com" },
Subject = "Test message from client",
Body = "<b>Test Mail</b><br>using <b>HTML from client</b>.",
IsBodyHtml = true
};
var client = new RestClient("http://localhost:53014/api/email");
var request = new RestRequest("SendMailMessage", Method.POST);
var json = request.JsonSerializer.Serialize(myMail);
request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
request.RequestFormat = DataFormat.Json;
var res = client.Execute(request);
Then construct the mail message in the action using the properties provided to the action.
public class EmailController : ApiController {
[HttpPost]
public async Task<IHttpActionResult> SendMailMessage([FromBody]Email message) {
if (ModelState.IsValid) {
var myMail = new System.Net.Mail.MailMessage();
myMail.Subject = message.Subject;
myMail.SubjectEncoding = System.Text.Encoding.UTF8;
myMail.Body = message.Body;
myMail.BodyEncoding = System.Text.Encoding.UTF8;
myMail.IsBodyHtml = message.IsBodyHtml;
myMail.From = new MailAddress("from#example.com");
foreach (var to in message.To) {
myMail.To.Add(to);
}
//...Code to send email
}
return BadRequest(ModelState);
}
}
Related
this is my client code
var client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
var multipart = new MultipartFormDataContent();
var jsonToSend = JsonConvert.SerializeObject(template, Formatting.None);
var body = new StringContent(jsonToSend, Encoding.UTF8, "application/json");
multipart.Add(body, "JsonDetails");
return client.PostAsync("jsons", multipart);
server code is
[HttpPost("jsons")]
public async Task<IActionResult> RequestJson([FromBody]Person person)
{
if (person != null)
{
return Ok("true");
}
return Ok("false");
person code
public class Person
{
public string Name { get; set; }
public string Position { get; set; }
}
when look in debug my post from client dont knock to server, in postman my post sending and i can see my object property
Just post the StringContent directly without the Multipart-Form:
var client = new HttpClient
{
BaseAddress = new Uri(BASE_URL)
};
var jsonToSend = JsonConvert.SerializeObject(template, Newtonsoft.Json.Formatting.None);
var body = new StringContent(jsonToSend, Encoding.UTF8, "application/json");
return client.PostAsync("jsons", body)
when i run the client code it gives me a 500 error.Since am still new to web api subject , I really appreciate the help, to identify where was my mistake.
using (HttpClient client = new HttpClient())
{
ObjHeader.listRtnTalleySheetHeader = lstRtnTalleySheetHeader;
ObjHeader.listRtnTalleySheetDetail = lstRtnTalleySheetDetail;
client.BaseAddress = new Uri("http://---service---");
var url = "api/config/InsertTalleydetail/";
var alldetails = Newtonsoft.Json.JsonConvert.SerializeObject(ObjHeader);
HttpContent content = new StringContent(alldetails, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
val = "Ok";
else
val = "No";
}
return val;
which the ObjHeader is clsAllTalleyHeaderDetail ObjHeader = new clsAllTalleyHeaderDetail();
clsAllTalleyHeaderDetail is
public class clsAllTalleyHeaderDetail
{
public ObservableCollection<clsTalleySheetHeader> listRtnTalleySheetHeader { get; set; }
public ObservableCollection<clsTalleySheetDetail> listRtnTalleySheetDetail { get; set; }
}
then my WEb API
[HttpPost]
public HttpResponseMessage InsertTalleydetail([FromBody] clsAllTalleyHeaderDetail obj)
{
return todoService.InsertTalleydetail(obj.listRtnTalleySheetHeader , obj.listRtnTalleySheetDetail );
}
1) For your main api you have to set Content-Type header to application/json in HttpClient like
client.DefaultRequestHeaders.Add("Content-Type","application/json");
2) For your sample api you have to set Content-Type header to application/json in postman with your raw format.
The ValidateMinMaxListCountAttribute validation attribute works in my unit test, but does not when used in WebAPI framework?
For example inside the unit test the "isValid" returns true, yet in the controller it fails. I'm guessing some kind of serialization issue?
Anyone have any ideas?
[TestCategory("ServiceTests")]
[TestMethod]
public void CallServiceCalc()
{
var client = new RestClient();
client.BaseUrl = new Uri("https://localhost:44379");
client.Authenticator = new HttpBasicAuthenticator("eric.schneider", "password");
var request = new RestRequest();
request.Resource = "api/Calculation/Calculate";
CoralRequest coralReq = new CoralRequest();
coralReq.ModelId = 1;
coralReq.ModelName = "2018";
coralReq.BasePlan = new BeneifitsPlanInputs();
coralReq.Plans.Add(new BeneifitsPlanInputs());
request.AddBody(coralReq);
ValidateMinMaxListCountAttribute va = new ValidateMinMaxListCountAttribute(1, 999);
bool isValid = va.IsValid(coralReq.Plans);
IRestResponse response = client.Execute(request);
Assert.IsTrue(response.StatusCode == System.Net.HttpStatusCode.OK, "Should not be ok");
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ValidateMinMaxListCountAttribute : ValidationAttribute
{
public ValidateMinMaxListCountAttribute(int minimum, int maximum)
{
this.MinimumCount = minimum;
this.MaximumCount = maximum;
}
public int MinimumCount { get; set; }
public int MaximumCount { get; set; }
public override bool IsValid(object value)
{
var list = value as ICollection;
if (list != null)
{
if (list.Count > MaximumCount) { return false; }
if (list.Count < MinimumCount) { return false; }
return true;
}
return false;
}
}
public class CoralRequest
{
public CoralRequest()
{
this.Plans = new List<BeneifitsPlanInputs>();
}
/// <summary>
///
/// </summary>
[ValidateMinMaxListCount(1, 99, ErrorMessage = "Must have between 1 and 99 plans")]
public IList<BeneifitsPlanInputs> Plans { get; set; }
}
Based on one of your other questions, which seems to be related, you show that the controller action looks like...
[HttpGet("{mock}")]
public ActionResult<CoralResult> CalculateMock(CoralRequest mock)
While in the test, a GET request is being made, GET requests do not have a BODY, and yet you add one to the request. Meaning that most likely the model is not being populated/bind to correctly on the server
This looks like a classic XY problem
That action should most likely be a POST request if you want to get the BODY of the request, and the action should be refactored to explicitly state where the data should be attained from.
[Route("api/[controller]")]
public class CalculationController: Controller {
//POST api/Calculation/Calculate
[HttpPost("[action]")]
public ActionResult<CoralResult> Calculate([FromBody]CoralRequest model) {
if(ModelState.IsValid) {
CoralResult result = new CoralResult();
//...do something with model and populate result.
return result;
}
return BadRequest(ModelState);
}
}
Which should now match more closely to what was being attempted in the integration test
[TestCategory("ServiceTests")]
[TestMethod]
public void CallServiceCalc() {
var client = new RestClient();
client.BaseUrl = new Uri("https://localhost:44379");
client.Authenticator = new HttpBasicAuthenticator("eric.schneider", "password");
var request = new RestRequest(Method.POST); //<-- POST request
request.Resource = "api/Calculation/Calculate";
request.AddHeader("content-type", "application/json");
CoralRequest coralReq = new CoralRequest();
coralReq.ModelId = 1;
coralReq.ModelName = "2018";
coralReq.BasePlan = new BeneifitsPlanInputs();
coralReq.Plans.Add(new BeneifitsPlanInputs());
request.AddJsonBody(coralReq); //<-- adding data as JSON to body of request
IRestResponse response = client.Execute(request);
Assert.IsTrue(response.StatusCode == System.Net.HttpStatusCode.OK, "Should be HttpStatusCode.OK");
}
The model binder should now be able to validate the model after binding it and passing it to the action.
Reference Model Binding in ASP.NET Core
I was able to write the code to perform GET operation from a web API. But, I'm not able to POST. I think the problem is with the JSON object. I'm able to POST if the parameters are sent via URL but I'm unable to do so if it's a JSON Object. Eg: The POST requires me to send ModelID, CustomerID via URL and ReferenceString as a JSON object.
Data to POST
ModelID = 3345
CustomerID =1V34858493
ReferenceID is a JSON string[]
[
{
"ReferenceId": "a123"
}
]
Main
static void Main(string[] args)
{
// JavaScriptSerializer serializer = new JavaScriptSerializer();
string patientServiceResponse = PostRequest( string.Format("https://url.com/api/{0}/{1}/taskOrders", 3345, "1V34858493"));
Debug.Write(patientServiceResponse);
}
POST Request
private static string PostRequest(string url)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
httpWebRequest.Accept = "application/json; charset=utf-8";
string sContentType = "application/json";
JObject oJsonObject = new JObject();
oJsonObject.Add("ReferenceId", "a123");
HttpClient oHttpClient = new HttpClient();
var oTaskPostAsync = oHttpClient.PostAsync(url, new StringContent(oJsonObject.ToString(), Encoding.UTF8, sContentType));
//return
}
Can you please correct me where I'm going wrong.
Thanks to Mason! I wrote the code to POST the data to the web API using HttpWebRequest.
Main
static void Main(string[] args)
{
string patientServiceResponse = PostRequest( string.Format("https://url.com/api/{0}/{1}/taskOrders", 3345, "1V34858493"));
Debug.Write(patientServiceResponse);
}
POST
private static string PostRequest(string url)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "[ { \"ReferenceId\": \"a123\" } ]";
Debug.Write(json);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
try
{
using (var response = httpWebRequest.GetResponse() as HttpWebResponse)
{
if (httpWebRequest.HaveResponse && response != null)
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
}
}
}
catch (WebException e)
{
if (e.Response != null)
{
using (var errorResponse = (HttpWebResponse)e.Response)
{
using (var reader = new StreamReader(errorResponse.GetResponseStream()))
{
string error = reader.ReadToEnd();
result = error;
}
}
}
}
return result;
}
POST function will look like this.
[HttpPost]
[Route("{modelId}/{customerId}")]
public IHttpActionResult Add(string modelId, string customerId, REFDto referenceId)
{
return Ok();
}
Create a DTO class for reference Id
public class REFDto
{
public string referenceId { get; set; }
}
API Client call :
using (var client = new HttpClient())
{
var modelId = "3345";
var customerId = "1V34858493";
var url = $"https://url.com/api/{modelId}/{customerId}/taskOrders";
JObject oJsonObject = new JObject();
oJsonObject.Add("referenceId", "ref123");
var response = await client.PostAsync(url, new StringContent(oJsonObject.ToString(), Encoding.UTF8, "application/json"));
Console.WriteLine(response);
}
I have created the following restfull web service:
Interface
[ServiceContract]
public interface ISIGService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetTicket/")]
Ticket GetTicket(string user, string pwd);
}
Implementation
public class SIGService : ISIGService
{
public Ticket GetTicket(string user, string pwd)
{
return new Ticket()
{
Usuario = "xx",
UsuarioNombre = "xxx",
UsuarioId = "xxx"
};
}
Contract
[DataContract]
public class Ticket
{
[DataMember]
public int UsuarioId { get; set; }
[DataMember]
public string UsuarioNombre { get; set; }
[DataMember]
public string Usuario { get; set; }
}
I need to consume this service, from a web application, and get the typed object Ticket, I have included a service reference for this.
Server side code:
string urlService =
String.Format("http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'",
usuario, password);
var request = (HttpWebRequest)WebRequest.Create(urlService);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
I put a text variable just to get something, sort of lost here.
I don't seem to get this object, could you give some pointers on this?
Most likely, you just need to change your URL from
http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'
to using the proper REST syntax (since you're using a REST service):
http://localhost:22343/SIGService.svc/GetTicket/{user}/{pwd}
Sample:
http://localhost:22343/SIGService.svc/GetTicket/daniel/topsecret
No ? or user= or single quotes necessary ....
With this, the value from {0} will be passed into the user parameter, and the value from {1} to the pwd parameter.
For consuming the service, I would recommend you check out the excellent RestSharp library which makes using your REST service a breeze.
Your code would look something like this:
// set up the REST Client
string baseServiceUrl = "http://localhost:22343/SIGService.svc";
RestClient client = new RestClient(baseServiceUrl);
// define the request
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.RequestFormat = DataFormat.Xml;
request.Resource = "GetTicket/{user}/{pwd}";
request.AddParameter("user", "daniel", ParameterType.UrlSegment);
request.AddParameter("pwd", "top$ecret", ParameterType.UrlSegment);
// make the call and have it deserialize the XML result into a Ticket object
var result = client.Execute<Ticket>(request);
if (result.StatusCode == HttpStatusCode.OK)
{
Ticket ticket = result.Data;
}