Passing JSON to WebApi in ASP.NET MVC 4 using .NET Framework 4.5 - asp.net-mvc-4

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.

Related

RestSharp RestClient not working with ASP.NET Core [FromForm]

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).

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?

I have developed my application webforms separately. Now I have added Web Api MVC while calling method of controller I am getting following error

I have developed my application webforms separately. Now I have added Web Api while calling method of controller I am getting following error:
No MediaTypeFormatter is available to read an object of type 'List`1' from content with media type 'text/html'.
Here is my controller:
[Authorize]
[RoutePrefix("api/Announce")]
public class AnnouncementController : ApiController
{
// GET api/<controller>
[Route("GetData")]
[HttpGet]
public List<EAnnouncement> Get(string code)
{
return AnnouncementC.getdata(code);
}
[Route]
[HttpPost]
public void Post(EAnnouncement announcement)
{
AnnouncementC.insert(announcement);
}
}
Here I am calling the method:
public static IQueryable<EAnnouncement> addressBookGrid_GetData(string code)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:49540");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("api/Announce/" + code).Result;
// response.EnsureSuccessStatusCode();
List<EAnnouncement> addressBooks = response.Content.ReadAsAsync<List<EAnnouncement>>().Result;
return addressBooks.AsQueryable();
}
You are not setting the content type of the request. Set the value using StringContent constructor.
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:49540");
client.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "RelativAaddressOfController");
request.Content = new StringContent("", Encoding.UTF8, "application/json");

Access Cookies inside unit test in AspNet.TestHost.TestServer context on ASP.NET 5 / MVC 6

There is no easy way to get an access to a CookieContainer in response object running integration tests with AspNet.TestHost.TestServer. Cookies have to be set by the controller action. What is the best way to achieve that?
var client = TestServer.Create(app =>
{
app.UseMvc(routes =>
routes.MapRoute("default", "{controller}/{action}/{id?}"));
app.UseIdentity();
}).CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, "account/login");
var response = await client.SendAsync(request);
// how to get an access to cookie container ?????????
// response.Cookies prop doesn't exist
Assert.NotEmpty(response.Cookies["auth"]);
Solution that I see is to extend instance of the TestServer, return instance of a class CustomClientHandler : ClientHandler and override the whole process of sending a request in that handler, but it needs literally to change all logic except relatively small code of the TestServer.
Any better suggestion how to implement an access to Cookies in a response?
As an addition to #Oleh's response, you can achieve the same without reflection on newer frameworks like .NET 4.6.1+ / .NET Core
public class TestHttpClientHandler : DelegatingHandler
{
[NotNull]
private readonly CookieContainer cookies = new CookieContainer();
public TestHttpClientHandler([NotNull] HttpMessageHandler innerHandler)
: base(innerHandler) { }
[NotNull, ItemNotNull]
protected override async Task<HttpResponseMessage> SendAsync([NotNull] HttpRequestMessage request, CancellationToken ct)
{
Uri requestUri = request.RequestUri;
request.Headers.Add(HeaderNames.Cookie, this.cookies.GetCookieHeader(requestUri));
HttpResponseMessage response = await base.SendAsync(request, ct);
if (response.Headers.TryGetValues(HeaderNames.SetCookie, out IEnumerable<string> setCookieHeaders))
{
foreach (SetCookieHeaderValue cookieHeader in SetCookieHeaderValue.ParseList(setCookieHeaders.ToList()))
{
Cookie cookie = new Cookie(cookieHeader.Name.Value, cookieHeader.Value.Value, cookieHeader.Path.Value);
if (cookieHeader.Expires.HasValue)
{
cookie.Expires = cookieHeader.Expires.Value.DateTime;
}
this.cookies.Add(requestUri, cookie);
}
}
return response;
}
}
I've implemented custom HttpMessageHandler that tracks cookies.
It uses reflection to invoke the actual handler and just reads/sets Cookie headers.
class TestMessageHandler : HttpMessageHandler
{
delegate Task<HttpResponseMessage> HandlerSendAsync(HttpRequestMessage message, CancellationToken token);
private readonly HandlerSendAsync nextDelegate;
private readonly CookieContainer cookies = new System.Net.CookieContainer();
public TestMessageHandler(HttpMessageHandler next)
{
if(next == null) throw new ArgumentNullException(nameof(next));
nextDelegate = (HandlerSendAsync)
next.GetType()
.GetTypeInfo()
.GetMethod("SendAsync", BindingFlags.NonPublic | BindingFlags.Instance)
.CreateDelegate(typeof(HandlerSendAsync), next);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("Cookie", cookies.GetCookieHeader(request.RequestUri));
var resp = await nextDelegate(request, cancellationToken).ConfigureAwait(false);
if (resp.Headers.TryGetValues("Set-Cookie", out var newCookies))
{
foreach (var item in SetCookieHeaderValue.ParseList(newCookies.ToList()))
{
cookies.Add(request.RequestUri, new Cookie(item.Name, item.Value, item.Path));
}
}
return resp;
}
}
And then you create your HttpClient like this:
var httpClient = new HttpClient(
new TestMessageHandler(
server.CreateHandler()));
TestMessageHandler now takes care of tracking cookies.
For a dotnet core integration test approach like the one described in the docs here, you can get cookies with the following code:
public class CookieTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public CookieTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
[Fact]
public async Task GetPage_ShouldSetCookie_CookieSet()
{
using (var client = _factory.CreateClient())
{
var response = await client.GetAsync("/cookie_setting_url");
response.EnsureSuccessStatusCode();
//or other assertions
Assert.True(response.Headers.TryGetValues(HeaderNames.SetCookie, out IEnumerable<string> cookies));
}
}
}
The proper way, using minimal code getting cookies
in Asp.Net Core Functional Tests is as follows, (I leave out init code for setting up WebApplicationFactory, which is known stuff)
The given examples above, require either reflection (Since I think MS made a design bug on not exposing the default handlers) or require cookie parsing, which is annoying in 2023.
private (HttpClient, CookieContainerHandler) GetHttpClient()
{
CookieContainerHandler cookieContainerHandler = new();
var client = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication(defaultScheme: "YourSchema")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
"TestAzure", options => { });
});
}).CreateDefaultClient(cookieContainerHandler);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(scheme: "YourSchema");
return (client, cookieContainerHandler);
}
[Fact]
public async Task MyUnitTest()
{
// Arrange
var (client, cookieHandler) = GetHttpClient();
// Act PUT/GET/POST etc
var response = await client.PutAsync("youruri", null);
var sessionCookie = cookieHandler.Container.GetAllCookies().FirstOrDefault(f => f.Name == "yourcookie"); // note this ignores cookie domain policy
}

xamarin web API authentication

I am very new to Xamarin and mobile development and I am currently involved in developing a sample application with authentication. We are using our internal Web API service to authenticate and can someone guide me how to proceed in this case. I am planning to use MvvmCross framework in my development. I am NOT using Xamarin forms and using the platform specific project for Android as part of my initial development. Any help really appreciated.
Here is the sample code I am using to call my WebAPI
public async Task<HttpResponseMessage> PutAsync<T>(string url,T content)
{
using (var client = new HttpClient(new NativeMessageHandler()))
// using (var client = new HttpClient())
{
string json = JsonConvert.SerializeObject(content);
var address = string.Format("{0}{1}", WebService.BaseUrl, url);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PutAsync(new System.Uri(address), httpContent);
return response;
}
}`enter code here`
I was able to call a sample get request using http but failing on
https
request. I am testing on android 4.4 Kit kat device
System.Net.Http.HttpMessageHandler handler = new NativeMessageHandler(false,true);
.Net.Http.HttpClient client = (handler == null) ? new System.Net.Http.HttpClient() :new System.Net.Http.HttpClient(new NativeMessageHandler(false,true));
result = client.GetAsync("https://httpbin.org/ip");
var stream = await result.Result.Content.ReadAsStringAsync();
If your service supports OAuth (what I'd recommend for apps), you can use the Xamarin.Auth library to Authenticate your users. https://www.nuget.org/packages/Xamarin.Auth/
Here is a tutorial how to use it: https://developer.xamarin.com/guides/xamarin-forms/web-services/authentication/oauth/
I am posting my code which I got it worked.
using System.Threading.Tasks;
using Newtonsoft.Json;
using ModernHttpClient;
using System.Net.Http;
using System.Text;
namespace App.Portable
{
public interface IHttpService
{
Task<T> ReadContentAsync<T>(Task<HttpResponseMessage> response);
Task<HttpResponseMessage> GetAsync(string url);
Task<string> PutAsync<T>(string url,T content);
}
public class HttpService : IHttpService
{
public async Task<HttpResponseMessage> GetAsync(string url)
{
throw new HttpRequestException();
}
public async Task<string> PutAsync<T>(string url,T content)
{
HttpMessageHandler handler = new NativeMessageHandler(false,true);
HttpClient client = (handler == null) ? new HttpClient() :new HttpClient(new NativeMessageHandler(false,true));
string json = JsonConvert.SerializeObject(content);
var address = string.Format("{0}{1}", WebService.BaseUrl, url);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
var response = client.PutAsync(new System.Uri(address), httpContent);
var stream = await response.Result.Content.ReadAsStringAsync();
return stream;
}
}
}