RestSharp RestClient not working with ASP.NET Core [FromForm] - asp.net-core

Hi I am writing integration test for my asp.net core project and i am trying to use RestSharp RestClient to send Form Data. My Code is working fine as i am getting the desired result if use postman but if i copy restsharp code from postman and try to implement in my test case its not reaching the controller. Following is my code
Postman -
Test Code -
[Test]
public void ConvertToJson_CSV()
{
var client = new RestClient("https://localhost:44355/GroupContacts/ConvertToJson");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
//request.AddFile("files", #"C:\Users\RanaBoy\Desktop\ZTT\ZTTTestFiles\sample500.csv");
request.AddFile("files", System.IO.File.ReadAllBytes(#"C:\Users\RanaBoy\Desktop\ZTT\ZTTTestFiles\sample500.csv"), "sample500.csv");
request.AddParameter("optInStatus", "1");
request.AddParameter("SessionId", _SessionId);
request.AddParameter("AccountId", _AccountId);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("content-type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
request.AlwaysMultipartFormData = true;
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
//Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}
Controller Code -
[HttpPost]
[Route("ConvertToJson")]
[Consumes("multipart/form-data")]
public async Task<IActionResult> ConvertToJson([FromForm] ConvertFileToJsonCommand command)
{
var result = await _mediator.Send(command);
return Ok(result.ResultJson);
}
Model Class -
public class ConvertFileToJsonCommand : IRequest<ConvertFileToJsonResponse>
{
public int AccountId { get; set; }
public string SessionId { get; set; }
public List<IFormFile> files { get; set; }
public int optInStatus { get; set; }
}

Postman doesn't generate the correct code for RestSharp. For example, your code sets the content-type header twice.
The following code should produce the correct request:
public async Task ConvertToJson_CSV()
{
var client = new RestClient("https://localhost:44355/GroupContacts/ConvertToJson");
var request = new RestRequest(Method.POST)
.AddFile("files", "sample500.csv", "C:\Users\RanaBoy\Desktop\ZTT\ZTTTestFiles\sample500.csv")
.AddParameter("optInStatus", "1")
.AddParameter("SessionId", _sessionId)
var response = await client.ExecuteAsync(request);
Console.WriteLine(response.Content);
//Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
}
Notice that the code uses RestSharp 107. If for some reason it won't work, you can check the difference between Postman request and RestSharp request using HttpTracer (check the docs).

Related

Could not post value to web API using IFormFile

i have a web application that does an action to upload image to api
the code like this
[HttpPost]
public async Task<IActionResult> Upload([FromForm] UploadModel model)
{
var upload = AccountApi.UploadFile(model);
return Ok("OK");
}
public static object UploadFile(UploadModel model)
{
RestClient client = InitClient();
request.Resource = "Account/UploadFile";
request.Method = Method.POST;
request.AddJsonBody(model);
IRestResponse<object> response = client.Execute<object>(request);
return response.Data;
}
public class UploadModel
{
public long UserId { get; set; }
public string Token { get; set; }
public IFromFile File { get; set; }
}
and there's a web API to handle Rest request above
the code like this
[HttpPost("UploadFile")]
public async Task<object> UploadFileAction(UploadModel model)
{
// the code handle upload file request here
return "Success";
}
my issue is the UploadModel model in web application contains the right value that requested from front-end (UserId = 10, Token = "eyJ..........", File = [object])
but when it posted to API, the 3 properties in UploadModel didn't get the value posted from web application (UserId = 0, Token = null, File = null)
could you help me to find the solution for this. Thanks all
I found the solution myself.
instead of using IFormFile to post, I serialized the image file to a base64 string and post it over API. and in API, I convert it to File object
Thanks for following my question

How to consume Azure Fuction from MVC Controller

I have created and published an Azure Function (HTTP Triggered) for a search functionality. When I type an ID in a search box and click on "Search", it should call the Azure Function and get the result back.
How to integrate the Azure Function with my Controller Action in .NETCore?
Here is the example how you could call your azure function into the controller.
I have a simple azure function which return a name and email once its called. Let's see the below example:
public class InvokeAzureFunctionController : ApiController
{
// GET api/<controller>
public async System.Threading.Tasks.Task<IEnumerable<object>> GetAsync()
{
HttpClient _client = new HttpClient();
HttpRequestMessage newRequest = new HttpRequestMessage(HttpMethod.Get, "http://localhost:7071/api/FunctionForController");
HttpResponseMessage response = await _client.SendAsync(newRequest);
dynamic responseResutls = await response.Content.ReadAsAsync<dynamic>();
return responseResutls;
}
}
Test Function For Controller Invocation:
public static class FunctionForController
{
[FunctionName("FunctionForController")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
if (name == null)
{
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
name = data?.name;
}
ContactInformation objContact = new ContactInformation();
objContact.Name = "From Azure Function";
objContact.Email = "fromazure#function.com";
return req.CreateResponse(HttpStatusCode.OK, objContact);
}
}
Simple ContactInformation Class I have Used:
public class ContactInformation
{
public string Name { get; set; }
public string Email { get; set; }
}
PostMan Test:
I have called the controller action from Post Man and its successfully return data from my local azure function through the local controller action. See the screen shot below:
Hope you understand. Just plug and play now.

Passing JSON to WebApi in ASP.NET MVC 4 using .NET Framework 4.5

I'm trying to pass model from Restful API. My code is:
public class RestApiInvocations<T>
{
public HttpResponseMessage Post(string url, T model)
{
HttpResponseMessage result = null;
HttpClient client = new HttpClient();
try
{
result = client.PostAsJsonAsync(url, model).Result;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
return result;
}
}
In my API controller, I added the FromUri and FromBody attributes on the incoming parameters.
But my HttpClient object doesn't allow me to add a Content-Type header. I can add an Accept header, so I tried to add an accept header with application/json, but without result. Any suggestions?
Thanks for your help!
private const string _Uri = "/ROUTE_TO_ACTION";
public ReturnModel AddInvoice(SomeModel model)
{
var uri = string.Format(_Uri);
var response = ServiceClient().PostAsJsonAsync(uri, model).Result;
var result = response.Content.ReadAsAsync<ReturnModel>().Result;
return result;
}
private HttpClient ServiceClient()
{
var client= new HttpClient();
client.BaseAddress = new Uri("YOUR_BASE_URL_TO_API"); //"http://localhost:8080/"
client.Timeout = TimeSpan.FromMinutes(3);
}
Set your Urls/Endpoints and Run it.
And test you Api Endpoints on POSTMAN before writing the code.

How to create an ASP.NET Core API controller action for HttpPost that can accept a request that has content of type MultipartFormDataContent

I am working on an ASP.NET Core 2.0 API in VS2017.
I want to create a controller action for an HTTP Post method that accept string and byte[] values that I will then use to create records in my SQL database.
From what I understand, if I want to post both string data and a byte[] that represents a file, I have to use MultipartFormDataContent as the type of content in the request from my client.
So, on the API controller action, how is that mapped? Can I have a DTO class in the API that has properties for both the string values and the byte[] value and have it passed into the API controller action via the [FromBody]UploadsDto dto
For example, have a DTO class like this...
public class UploadFileRecordForCreationDto
{
public int LocationId { get; set; }
public string FileName { get; set; }
public byte[] UploadedFile { get; set; }
}
Then have a controller action with this signature...
[HttpPost(Name = "CreateUploadFileRecord")]
public IActionResult CreateUploadFileRecord([FromBody]UploadFileRecordForCreationDto dto)
{
...
...
...
return CreatedAtRoute("GetUploadedFileFile", new { id = linkedResourceToReturn["Id"] }, linkedResourceToReturn);
}
And then have that API action accept a request created using something similar to what I am doing with this test console application on the client side;
static async Task CreateUploadFileRecordAsync()
{
httpClient.BaseAddress = new Uri("https://localhost:44369");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string relativeUrl = "/api/UploadFilesManager";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, relativeUrl);
HttpResponseMessage response = new HttpResponseMessage();
using (var content = new MultipartFormDataContent("--UploadTest"))
{
var values = new[]
{
new KeyValuePair<string,string>("LocationId","1"),
new KeyValuePair<string,string>("FileName","TestFile-01.txt"),
};
foreach (var keyvaluepair in values)
{
content.Add(new StringContent(keyvaluepair.Value, Encoding.UTF8, "application/json"), keyvaluepair.Key);
}
var fileContent = new ByteArrayContent(File.ReadAllBytes(#"C:\testfile-01.txt"));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue(DispositionTypeNames.Attachment)
{
Name = "UploadedFile",
FileName = "testfile-01.txt"
};
content.Add(fileContent);
request.Content = content;
response = await httpClient.SendAsync(request);
}
if (response.IsSuccessStatusCode)
{
string result = response.Headers.Location.ToString();
Console.WriteLine("Success:\n");
Console.WriteLine($"New Record Link: [{result}]\n");
}
else
{
Console.WriteLine($"Failed to create new UploadFile record. Error: {0}\n", response.ReasonPhrase);
}
}
If it doesn't just map to a DTO in the FromBody, can anyone provide an example of how to deal with this use case?

Rest API Calls with RestSharp calling ASP.NET Web API

I'm currently testing out writing a RESTful API with ASP.NET Web API. I'm using RestSharp on a client to simulate different calls.
I want to submit an application ID query string, and the body should be a collection of type "Log". Every time, the application ID get's posted by the body received by the server is always NULL.
Code on the server:
public class LogsController : ApiController
{
public HttpStatusCode Post(Guid ID, [FromBody] List<Log> logs)
{
if (logs != null)
return HttpStatusCode.OK;
else
return HttpStatusCode.PreconditionFailed;
}
}
public class Log
{
public Guid ErrorId { get; set; }
}
Code on the client:
static void Main(string[] args)
{
var client = new RestClient("http://localhost:36146/api");
var json = JsonConvert.SerializeObject(new List<Log>()
{
new Log { ErrorId = Guid.NewGuid()}
});
var request = new RestRequest("Logs", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddParameter("ID", Guid.NewGuid(), ParameterType.QueryString);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json; charset=utf-8");
request.AddBody(json);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
Console.Read();
}
public class Log
{
public Guid ErrorId { get; set; }
}
I thought I got this working, however no matter what I do now the "logs" parameter on the server is always NULL.
I think I've found the issue.
RestSharp implicitly uses the JsonSerializer when populating the body of the request. As I was also called the Serializer I think it caused issues with the formatting.
I've removed that call to the serializer and now I'm receiving a 200 back from the server.
Happy days.