Accept zip file using postman - .net-core

I have created api project in .Net Core application. I have also created Method to accept HttpRequestMessage as parameter. Now I am trying to call my api method using Postman with including file as body parameter, but my api method is not calling.
Here is code
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpPost]
public HttpResponseMessage PostFiles()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Request;
return result;
}}
Here is Postman request data
POST /api/values/PostFiles HTTP/1.1
Host: localhost:64226
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Cache-Control: no-cache
Postman-Token: 6adcc652-a4ab-3714-cc5e-770bd214ac7a
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="data"; filename=""
Content-Type:
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Here is the screen shot of my api call using postman.
Request body with file as parameter
Is there anything that I am missing?
Can you please help me out to call my web api with accepting file as parameter using Postman?

I think there's a problem with your route. Try this :
public class ValuesController : Controller
{
[Route("api/values/postfiles")]
[HttpPost]
public HttpResponseMessage PostFiles()
{
HttpResponseMessage result = null;
var files = Request.Form.Files;
return result;
}
}
Then try accessing the API at http://localhost:yourport/api/values/postfiles .
replace "yourport" in your port no.
You'll get the file in "fileStream" if the file is available.

In an ASP.NET Core application use IHostingEnvironment. Then you can call ContentRootPath and WebRootPath

Related

Different value when processing POST request in ASP.NET WEB API

I have a following situation which I have never seen before. I am using code below to declare a Post action.
[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> Insert(InsertRequest request)
{
var body = await Request.Content.ReadAsStringAsync();
}
Now, when I am sending request to this endpoint using Postman with Content-Type = Application/Json I get some value for request and empty string for body.
If I do PostAsJsonAsync with HttpClient to this endpoint I will get null for request and request content for body.
How is that possible?
To support POST you need to add attribute [FromBody] to the request parameter.
[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> Insert([FromBody] InsertRequest request)
{
var body = await Request.Content.ReadAsStringAsync();
}

Fineuploader dotnet core

I'm trying to get write Controller (in asp.net core) code to handle my fineuploader requests but it keeps failing to see the request data despite whatever combination of [FromForm] / [FromBody] / "Content-Type": 'application/json' I use. Here is my uploader config in the view page:
var uploader = new qq.FineUploader({
element: document.getElementById("uploader"),
request: {
endpoint: '#Url.Action("AddAttachment", "Util")',
customHeaders: {
"RequestVerificationToken": '#GetAntiXsrfRequestToken()',
"Content-Type": 'application/json'
}
},
And here is my controller code - not alot for now, I just literally want to see some data getting sent.
public JsonResult AddAttachment([FromForm] Object o){
//var x = HttpContext.Request;
//return Json(x);
if(o == null){
return Json("no data");
}else{
return Json(o);
}
}
and her is what I see fineuploader sending to the server via the network tab in the chrome devtools:
------WebKitFormBoundarySQwYoYovQOkoFU1f
Content-Disposition: form-data; name="test"
876
------WebKitFormBoundarySQwYoYovQOkoFU1f
Content-Disposition: form-data; name="qquuid"
9ba04b80-b3d8-4e2d-8068-792dd77253bd
------WebKitFormBoundarySQwYoYovQOkoFU1f
Content-Disposition: form-data; name="qqfilename"
dohPlayDat.PNG
------WebKitFormBoundarySQwYoYovQOkoFU1f
Content-Disposition: form-data; name="qqtotalfilesize"
3535659
------WebKitFormBoundarySQwYoYovQOkoFU1f
Content-Disposition: form-data; name="qqfile"; filename="dohPlayDat.PNG"
Content-Type: image/png
------WebKitFormBoundarySQwYoYovQOkoFU1f-
Can anyone see the mistake I'm making?
If everything's wired up correctly, you should be able to see your file via Request.Form.Files in the controller.
I was trying to get it as a byte array by action's parameters but had no luck. Try this instead.
The following snippet is an example of how you can bind all the fields from the file upload request, then use the file stream to write the file to a temporary file.
public async Task<IActionResult> Post(string qquuid, string qqfilename, int qqtotalfilesize, IFormFile qqfile)
{
// full path to file in temp location
var filePath = Path.GetTempFileName();
if (qqfile.Length > 0)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await qqfile.CopyToAsync(stream);
}
}
}
For more information about using .NET Core to upload files you can have a look over here : https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1

How to use Created (or CreatedAtAction / CreatedAtRoute) in an asp net core api

I'd like to inform consumers of my api about the location of the newly created object. I know there is Created() CreatedAtRoute() and CreatedAtAction() but I am unsure how to use it.
Here is what I've tried:
I have a Get resource to which I would like to point. It takes an ID as input:
[HttpGet("/${id}", Name = "GetProduct")]
[ProducesResponseType(typeof(Produkt), 200)]
public IActionResult Get([FromRoute] int id)
{
// some code...
return Ok(...);
}
When a product gets created via my POST route, I would like to point to this Resource via the Location header:
Attempt 1
[HttpPost]
[ProducesResponseType(typeof(Produkt), 200)]
public IActionResult CreateNewProduct([FromBody] ProduktDtoForCreate productFromBody)
{
//...
return CreatedAtRoute("GetProduct", new { id = productToCreate.Id }, productToCreate);
}
This returns a Location Header of: http://localhost:5000/$15003
Attempt 2
[HttpPost]
[ProducesResponseType(typeof(Produkt), 200)]
public IActionResult CreateNewProduct([FromBody] ProduktDtoForCreate productFromBody)
{
//...
return Created(new Uri($"{Request.Path}/{productToCreate.Id}", UriKind.Relative), productToCreate);
}
This one works and returns /api/v1.0/produkte/16004 but it seems like using the current request to point to the new location should not be needed. Also I am not sure if this is good practice?
CreatedAtAction gives the best output in my opinion. The following controller code will do what you need:
[Route("api/products")]
[ApiController]
public class ProductsController : ControllerBase
{
private readonly IProductRepository productRepository;
public ProductsController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
[HttpPost]
[Route("")]
[ProducesResponseType(StatusCodes.Status201Created)]
public ActionResult<Product> CreateProduct(ProductCreateDto product)
{
if (product is null)
return BadRequest(new ArgumentNullException());
var entity = productRepository.CreateProduct(product);
return CreatedAtAction(nameof(GetProduct), new { id = entity.ID }, entity);
}
[HttpGet]
[Route("{id}")]
public ActionResult<Product> GetProduct(int id)
{
return productRepository.GetProduct(id);
}
}
Issuing the following request:
POST http://localhost:5000/api/products HTTP/1.1
Host: localhost:5000
Connection: keep-alive
Content-Length: 25
Content-Type: application/json
{ "name": "ACME Widget" }
Will yield the following response:
HTTP/1.1 201 Created
Date: Mon, 12 Oct 2020 09:50:00 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Content-Length: 29
Location: http://localhost:5000/api/products/1
{"id":1,"name":"ACME Widget"}
In your route for the Get method, take both the leading / and the $ out (i.e. it should just be "{id}"). Having the leading / in there means that the route will be relative to the base of the application; taking it out makes the route for the method relative to the controller's base path instead. The $ is being treated as a literal character in the route, hence why it was appearing in the Location header in Attempt 1. Once you've made the changes, you should find that your CreatedAtRoute call works as you would expect.
Quoting RFC 7231:
The 201 (Created) status code indicates that the request has been
fulfilled and has resulted in one or more new resources being created.
The primary resource created by the request is identified by either a
Location header field in the response or, if no Location field is
received, by the effective request URI.
What identifies the resource depends on the context. In my interpretation, if the resource created resides at <request_uri>/<id>, the identifier can be just <id>.

Cannot post object from .net Client web-api web service

I have one .net client which tries to make http request to web api service
here is my Request:
public List<Category> GetCategories()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:54558/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Task<string> response = client.GetStringAsync("api/CategoryApi/");
List<Category> lstCategory = JsonConvert.DeserializeObjectAsync<List<Category>>(response.Result).Result;
return lstCategory;
}
public void Create(Category category)
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var stringContent = new StringContent(category.ToString());
HttpResponseMessage responseMessage = client.PostAsync("api/CategoryApi/", stringContent).Result;
}
and in my webapi
public IEnumerable<Category> GetCategories()
{
return categoryRepository.data;
}
public string PostCategory(Category category)
{
categoryRepository.add(category);
return "MessageOk";
}
SO when I make request to my GetCategories action of the web-api everything is OK.
and no matter what I do it seems that .net application cannot find the Post action of the web-api and I never actually see entering in Postcategory method
as I have also put breakpoints here.
I only get the error
atusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Pragma: no-cache
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNccG9zdGdyZXNcRGVza3RvcFxXZWJBcGlTZXJ2aWNlXFdlYkFwaVNlcnZpY2VcYXBpXENhdGVnb3J5QXBpXA==?=
Cache-Control: no-cache
Date: Sat, 13 Jun 2015 17:55:16 GMT
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Content-Length: 1022
Content-Type: application/json; charset=utf-8
Expires: -1
}}
What may be the issue. Thak you in advance
You are posting just a Category.ToString which if you didn't override ToString to be a Json or XML string, it will fail on the server side because there is no way to deserialize the content into a Category object. You should serialize the Category on the client before posting it. Also make sure your request headers include the proper Content-Type of application/json. By posting StringContent, the Content-Type won't be application/json. You are setting the Accept header, but that only describes the data coming back to your client, not the data you are posting. One last thing, I would not use the same HttpClient for both the get and the post request. Each method should use it's own HttpClient so you don't have any extra headers depending on the call.

Can't set ISO-8859-1 as charset of web-api response

I need to set charset ISO-8859-1 for the responses of my web api controllers, and not UTF-8.
The controller for testing returns a POCO object like this:
public class StudyCaseController : ApiController
{
...
// GET: api/StudyCase/5
public Study Get(int id)
{
...
}
}
I've tried to set <globalization requestEncoding="iso-8859-1" responseEncoding="iso-8859-1"/> in the Web.config, but testing with a fiddler request like this:
GET http://localhost:45988/api/StudyCase/1 HTTP/1.1
User-Agent: Fiddler
Host: localhost:45988
Accept: text/xml
I've got a response like this:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B? QzpcTUVESE9NRVxEZXNhcnJvbGxvQ1xQcm95ZWN0b3NcVmlld0NhcE1hblxWaWV3Q2FwTWFuXGFwaVxT dHVkeUNhc2VcMQ==?=
X-Powered-By: ASP.NET
Date: Tue, 24 Mar 2015 11:36:13 GMT
Content-Length: 1072
<?xml version="1.0"?>
... etc...
I've also tried to specify the charset at the request with Accept-Charset: iso-8859-1 but the same result.
For more info, i've tested it with IIS Express and IIS Server.
Thanks.
You can set supported encodings for formatters in HttpConfiguration class. 28591 is codepage for ISO-8859-1 (Latin 1).
config.Formatters.Add(new XmlMediaTypeFormatter());
config.Formatters[0].SupportedEncodings.Clear();
config.Formatters[0].SupportedEncodings.Add(Encoding.GetEncoding(28591));
Dealing with the problem my self, I found out that the problem was indeed the XML MediaTypeFormatter.
It does not support ISO-8859-1 and without the ability to change the server-side code I was forced to use another MediaTypeFormatter
https://www.nuget.org/packages/NetBike.Xml.Formatting/
or in nuget console
Install-Package NetBike.Xml.Formatting
This solved my problem (in a project using Web API 2).
Here is a demonstration of one way to set this using the HttpClient
private static HttpClient httpClient;
private static MediaTypeFormatter formatter;
private static List<MediaTypeFormatter> formatters;
public static void loadSettings()
{
//httpClient settings are set here
formatters = new List<MediaTypeFormatter>();
formatter = new NetBike.Xml.Formatting.NetBikeXmlMediaTypeFormatter();
formatters.Add(formatter);
}
public static async Task<HttpResponseMessage> GetContent(string requestMethod)
{
try
{
var returnValue = await httpClient.GetAsync(requestMethod);
return returnValue;
}
catch (Exception ex)
{
Debug.WriteLine("Communicator.GetXml: " + ex.Message);
}
return null;
}
public static async void testStuff()
{
var httpResponse = await GetContent("http://someDomain.com/someMethod");
MyModelObject myModel = await httpResponse.Content.ReadAsAsync<MyModelObject>(formatters);
}
What you want to do, is to set this as a default formatter for the whole project.
-EDIT-
Microsoft argues that this behavior is intended.
https://connect.microsoft.com/VisualStudio/feedback/details/958121
I have experienced issues with the NetBike Formatter, when formatting advanced XML objects, and even have a case where it writes BOM to the output.
Therefore I do not recommend it above the default MediaTypeSerializer, instead the solution falls back to the old "it depends"
That looks like this in code
List<MediaTypeFormatter> formatters = new List<MediaTypeFormatter>();
MediaTypeFormatter badencodingFormatter = new NetBike.Xml.Formatting.NetBikeXmlMediaTypeFormatter();
badencodingFormatter.SupportedEncodings.Clear();
badencodingFormatter.SupportedEncodings.Add(Encoding.GetEncoding("ISO-8859-1"));
MediaTypeFormatter defaultFormatter = new CustomXmlMediaTypeFormatter();
formatters.Add(badencodingFormatter);
formatters.Add(defaultFormatter);
This makes sure that anoying encoding is handled by NetBike, but only in those (hopefully rare) cases

Resources