I have a webapi controller code looks like:
[HttpPost]
public HttpResponseMessage DownloadForms(FormCriteria criteria)
{
string downloadData = new FormsToCsvHelper(Umbraco, criteria).GetCsv();
return Request.CreateResponse(HttpStatusCode.OK, downloadData);
}
If i look at the data returned in debugger just before sending it back it looks like:
Created Date,IP,Form Name,Email address,Message,Full Name
31/05/2019 10:43:08,127.0.0.1,Contact form - test,test12#hotmail.com,test,Ismail Mayat
If I copy and paste it into file and save as csv it looks fine in excel.
However the data i actually get back looks like:
"Created Date,IP,Form Name,Email address,Message,Full Name\r\n31/05/2019 10:43:08,127.0.0.1,Contact form - test,test12#hotmail.com,test,Ismail Mayat"
The whole record set it wrapped in quote and the line feed is seen as a literal so when opening file in excel its all on one line.
There is a DelegatingHandler that fire but that is for a specific url request so for this request it does not do anything.
Anyone any ideas whats going on?
WebAPI will serialize the value as JSON by default, so that's why your value is enclosed in double quotes.
To get around this, you can use the StringContent class:
return new HttpResponseMessage(statusCode) {
Content = new StringContent(downloadData, Encoding.UTF8, "text/csv")
};
Related
In my web application (.net Core 2.2) I want to add the functionality of downloading a PDF file.
When the user clicks "download" - POST is sent to WebAPI and the server ask different server for PDF file by hardcoded URL (invisible to the user) and the file is passed to the user.
I was trying to use IHttpClientFactory
Startup:
services.AddHttpClient("demo", c =>
{
c.BaseAddress = new Uri("http://www.africau.edu/");
c.DefaultRequestHeaders.Add("Accept", "application/pdf");
});
Method for returns PDF file:
public async Task<FileStreamResult> GetPdfFile()
{
var client = _httpClientFactory.CreateClient("demo");
var uri = new UriBuilder(client.BaseAddress + "images/default/sample.pdf").Uri;
var stream = await client.GetStreamAsync(uri);
return new FileStreamResult(stream, new MediaTypeHeaderValue("application/pdf"));
}
Unfortunately it returns file download.json with: {"fileStream":{"needsDrain":true,"canRead":true,"canWrite":false,"canSeek":false
#EDIT
it seems that it's because I had Task<IActionResult> in my Controller instead of Task<FileStreamResult> but what if i prefer to returns ActionResult?
public async Task<IActionResult> GetPdf()
{
var result = await _service.GetPdfFile();
return Ok(result);
}
In your GetPdf method, you're passing a FileStreamResult to the Ok() method. This will serialize the FileStreamResult using the default serializer and send it to the client, hence why you're seeing the JSON.
Usually your service layer should not return an MVC WhateverResult object but rather an object intended to represent the actual data being retrieved - in your case this would be a PDF file. The easiest way to solve your particular case would probably be to do the following:
change GetPdfFile to return Task<FileStream> instead of Task<FileStreamResult>
remember to change its return statement to return stream;
change the return statement of GetPdf to return File(result, "application/pdf");
This will allow your service layer to return the PDF file as a stream, and then have your GetPdf endpoint return that stream as a file with the application/pdf file type.
I have a Web Api service that retrieves data from another service, which returns Json. I don't want to do anything to the response, I just want to return it directly to the client.
Since the response is a string, if I simply return the response, it contains escape characters and messy formatting. If I convert the response in to an object, the WebApi will use Json.Net to automatically format the response correctly.
public IHttpActionResult GetServices()
{
var data = _dataService.Get(); //retrieves data from a service
var result = JsonConvert.DeserializeObject(data); //convert to object
return Ok(result);
}
What I would like is to either A: Be able to return the exact string response from the service, without any of the escape characters and with the proper formatting, or B: Set a global settings that will automatically Deserialize the response so that the Web Api can handle it the way I am doing it already.
On Startup I am setting some values that describe how formatting should be handled, but apparently these aren't correct for what im trying to do.
HttpConfiguration configuration = new HttpConfiguration();
var settings = configuration.Formatters.JsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new DefaultContractResolver();
Do I need to create a custom ContractResolver or something? Is there one that already handles this for me?
Thanks
If you want to just pass through the json (Option A), you can do this
public IHttpActionResult GetServices() {
var json = _dataService.Get(); //retrieves data from a service
HttpContent content = new System.Net.Http.StringContent(json, Encoding.UTF8, "application/json");
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = content;
return ResponseMessage(response);
}
I've a JSP app. It uploads a file, but to do so the user has to authenticate using a name and a password. So my JSP file starts with:
//0.2.- We get the password
String password = (String) request.getParameter("pass"); // -> This returns NULL
//0.3.- We get the "uvus"
String uvus = (String) request.getParameter("uvus"); //-> This also returns NULL
//More code
So I'm trying to know why am I getting null from those variables.
I went to the form I was uploading, and look for the data that was being sent. Using Firefox Debug Tools, I saw:
So in fact, it was being sent.
As additional info, I'm building the request like this:
var pUvus = document.getElementById("uvus").value;
var pPassword = document.getElementById("pass").value;
var file = document.getElementById("userFile");
var formData = new FormData();
formData.append("upload", file.files[0]);
formData.append("uvus", pUvus);
formData.append("pass", pPassword);
xmlhttp.open("POST","uploadFile.jsp",true);
xmlhttp.send(formData);
At last, I would like to say that I can get vars from application object in the same JSP with no errors, and have received in another pair of JSP files vars at request object without more problems, so I think my fault should be in the way I'm building the request in Ajax, but I've no more clue about that...
Anyone can guide me?
Thanks for your help
Update: #rickz asked for how do I get the file and parse the request (what is done after my problem, trying to get the objects from the request scope):
List items;
items = servlet_up.parseRequest(request);
for(int i=0;i<items.size();i++)
{
FileItem item = (FileItem) items.get(i);
if (! item.isFormField())
{
request.getParameter() won't work for a multipart/form-data request.
If you are using org.apache.commons.fileupload then you should be using something like
if(item.isFormField()){
name = item.getFieldName();
...
}
I have an http module where I'm adding a response filter below for compression. This works for all API calls except for 1, the call to MetaData. If I remove the [BreezeController] decoration it works fine. I think it has to do with action filter attribute that converts the string return type into an HttpResponse return type with string content.
The error I'm getting is " Exception message: The stream state of the underlying compression routine is inconsistent."
I've done some testing where a method thats defined to return an HttpResponse works fine. So I think its the scenario where the method is defined to return string, and then the action filter changes it to HttpResponse at runtime.
Any ideas how I can get this to work?
Here's the response filter being added in BeginRequest:
HttpApplication app = (HttpApplication)sender;
// Check the header to see if it can accept compressed output
string encodings = app.Request.Headers.Get("Accept-Encoding");
if (encodings == null)
return;
Stream s = app.Response.Filter;
encodings = encodings.ToLower();
if (encodings.Contains("gzip"))
{
app.Response.Filter = new GZipStream(s, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "gzip");
}
Don't know the specifics of what you're doing but I know that the [BreezeController] attribute strips out filters and adds back just the ones that breeze wants.
One approach might be to define a separate controller (ModelMetadataController) that only serves the metadata. This controller doesn't have the [BreezeController] attribute; it's a plain old Web API controller.
Then you create a "Breeze controller" (ModelController) with all of the usual methods except the Metadata method.
You call the metadata controller from the client during app launch via MetadataStore.fetchMetadata just to get metadata.
Once you have populated a metadataStore in this fashion, you use it in your EntityManager which sends query and save requests to the "real" Web API data controller.
The client code might look something like this:
var ds = new breeze.DataService({
serviceName: 'breeze/Model' // the breeze query & save controller
});
var ms = new MetadataStore({
namingConvention: breeze.NamingConvention.camelCase, // assuming that's what you want
});
ms.addDataService(ds); // associate the metadata-to-come with the "real" dataService
var manager = new breeze.EntityManager({
dataService: ds,
metadataStore: ms
});
// the fun bit: fetch the metadata from a different controller
var promise = ms.fetchMetadata('breeze/ModelMetadata') // the metadata-only controller!
return promise; // wait on it appropriately
In PHP, it is possible to return a file to the browser by echoing it out with the correct header. You do not need to save a copy of it prior on the server.
So assuming I have a bunch of data I wish to return as a excel file - after creating the data structure using OpenXML, how can I serve the file to the user without saving it on the server first?
It's pretty simple actually. In your controller you can have an action like this:
public ActionResult GetMyFile()
{
//dynamically generate a file
System.IO.MemoryStream ms;
ms = GenerateFile(); // Some function to return a memorystream object
// return the file
return File(ms.ToArray(), "filename.pdf");
}
The user will be presented with a dialog box asking if they want to open the file or save it.
Write your data to a stream and return it from your controller action method in a FileStreamResult by setting the FileStream, ContentType and FileDownloadName properties.
[HttpGet]
public FileStreamResult MyFile()
{
var fileStreamResult = new FileStreamResult (GetMyContentAsStream(), "my/content-type-here");
fileStreamResult.FileDownloadName = "my-file-download-name.here";
return fileStreamResult ;
}
Update:
A short cut for doing this, is to use the Controller.File() method.
[HttpGet]
public FileStreamResult MyFile()
{
return File(GetMyContentAsStream(), "my/content-type-here");
}
You can save the contents of your dynamically generated file in a MemoryStream object. When you return a file you can use MemoryStream's GetBuffer() method to pass an array of bytes as the first parameter. Then set ContentType and FileDownloadName parameters.
Regards