I have a txt file which has some data in it. I would like to return the data in JSON format.
Why is it that when i do this in my controller, i am able to display the result (but not in JSON format):
public IHttpActionResult Get()
{
return new FileReaderClient("C:\\Users\\attsuap1\\Desktop\\1milliontest.txt");
}
However when i do this i get the result as: {"Data":{}}
public IHttpActionResult Get()
{
var result = new FileReaderClient("C:\\Users\\attsuap1\\Desktop\\1milliontest.txt");
return Ok(new { Data = result });
}
If i just return result:
public IHttpActionResult Get()
{
var result = (new FileReaderClient("C:\\Users\\attsuap1\\Desktop\\1milliontest.txt"));
return result;
}
I do get the data however it is not in the Json format that i want e.g. {"Data": "Allthecontentinhere"}. I tried return Json(result) that did not work too.
Here is my FileReaderClient.cs class
public class FileReaderClient : IHttpActionResult
{
private readonly string filePath;
private readonly string contentType;
public FileReaderClient(string filePath, string contentType = null)
{
this.filePath = filePath;
this.contentType = contentType;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.Run(() =>
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(File.OpenRead(filePath))
};
var contentType = this.contentType ?? MimeMapping.GetMimeMapping(Path.GetExtension(filePath));
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return response;
}, cancellationToken);
}
}
How can i edit my code such that the data in the file is returned in JSON format?
You can use 'JsonConvert' / NewtonSoft's JSON.Net Library,
var million_records;
using(StreamReader sr = new StreamReader(Server.MapPath("~/Uploads/1milliontest.json")))
{
million_records= JsonConvert.DeserializeObject<List<MillionData>>(sr.ReadToEnd());
}
return million_records;
Hope this helps.
--- N Baua
Related
I'm trying to write unit test for the following AspNetCore controller method:
[HttpGet]
public async Task<IActionResult> GetFile(string id)
{
FileContent file = await fileRepository.GetFile(id);
if (file == null)
return NotFound();
Response.Headers.Add("Content-Disposition", file.FileName);
return File(file.File, file.ContentType);
}
FileContent class:
public class FileContent
{
public FileContent(string fileName, string contentType, byte[] file)
{
FileName = fileName;
ContentType = contentType;
File = file;
}
public string FileName { get; }
public string ContentType { get; }
public byte[] File { get; }
}
Here is TestInitialize:
[TestInitialize]
public void TestInitialize()
{
repositoryMock = new Mock<IFileRepository>();
controller = new FilesController(repositoryMock.Object);
var httpContext = new Mock<HttpContext>(MockBehavior.Strict);
var response = new Mock<HttpResponse>(MockBehavior.Strict);
var headers = new HeaderDictionary();
response.Setup(x => x.Headers).Returns(headers);
httpContext.SetupGet(x => x.Response).Returns(response.Object);
controller.ControllerContext = new ControllerContext(new ActionContext(httpContext.Object, new RouteData(), new ControllerActionDescriptor()));
}
And test method:
[TestMethod]
public async Task GetShouldReturnCorrectResponse()
{
repositoryMock
.Setup(x => x.GetFile(It.IsAny<string>(), null))
.ReturnsAsync(new FileContent("test.txt", "File Content.", Encoding.UTF8.GetBytes("File Content.")));
IActionResult response = await controller.GetFile(DocumentId);
// .. some assertions
}
The test fails on the the following controller line:
return File(file.File, file.ContentType);
The exception:
System.FormatException: The header contains invalid values at index 0:
'File Content.'
at Microsoft.Net.Http.Headers.HttpHeaderParser`1.ParseValue(StringSegment
value, Int32& index) at
Microsoft.AspNetCore.Mvc.FileContentResult..ctor(Byte[] fileContents,
String contentType) at
Microsoft.AspNetCore.Mvc.ControllerBase.File(Byte[] fileContents,
String contentType, String fileDownloadName)
I can't figure out what is wrong here. Please advice.
When you add headers to the response, ASP.NET Core will validate known headers to make sure that they contain valid values. In your case, you are attempting to set the content type to "File Content." here:
repositoryMock
.Setup(x => x.GetFile(It.IsAny<string>(), null))
.ReturnsAsync(new FileContent("test.txt", "File Content.", Encoding.UTF8.GetBytes("File Content.")));
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
But File Content. is not a valid MIME type, so the validation of that value fails.
Instead, you should use an actual MIME type, e.g. text/plain since you also have plain text contents in your test:
repositoryMock
.Setup(x => x.GetFile(It.IsAny<string>(), null))
.ReturnsAsync(new FileContent("test.txt", "text/plain", Encoding.UTF8.GetBytes("File Content.")));
I need to build an html document and return it in my web api. All available answers on the net and the forum suggest using HttpResponseMessage. I would like to achieve this by IHttpActionResult. Below is what I have thus far:
[ResponseType(typeof(HttpResponseMessage))]
public async Task<IHttpActionResult> GetNotesViewModels()
{
var note = await GetHtmlText();
var response = new HttpResponseMessage();
response.Content = new StringContent(note);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return Ok(ResponseMessage(response));
}
I am not receiving what I would like. What is missing here?
You could implement your own HtmlResult, like following (free-handed):
public class HtmlActionResult : IHttpActionResult
{
public HtmlActionResult (HttpRequestMessage request, string content)
{
Request = request;
Content= content;
}
public string Content { get; private set; }
public HttpRequestMessage Request { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(ExecuteResult());
}
public HttpResponseMessage ExecuteResult()
{
var response = new HttpResponseMessage();
if (!string.IsNullOrWhiteSpace(Content))
response.Content = new StringContent(Content, Encoding.UTF8, "text/html");
response.RequestMessage = Request;
return response;
}
}
And use it like this:
public async Task<IHttpActionResult> GetNotesViewModels()
{
var note = await GetHtmlText();
return new HtmlActionResult(Request, note);
}
I have the following Action in my layouts Controller
public JsonResult getlayouts(int lid)
{
List<layouts> L = new List<layouts>();
L = db.LAYOUTS.Where(d => d.seating_plane_id == lid).ToList()
return new JsonResult { Data = L, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
I am calling this Action from another controller like so:
layoutsController L = new layoutsController();
JsonResult result = L.getlayouts(lid);
My question is: how can I get the data from result object?
Well, have a look how you're building the object:
new JsonResult { Data = L, JsonRequestBehavior = JsonRequestBehavior.AllowGet }
You're setting the L variable to a property called Data. So just read that property:
List<layouts> L = (List<layouts>)result.Data;
There's nothing special about the fact that it's an MVC controller action.
You're simply calling a method which returns an object that was constructed in the method, and reading properties from that object. Just like any other C# code.
I have my class:
public class ResponseJson
{
public string message { get; set; }
public bool success { get; set; }
}
in my method SendEmail
private async Task<JsonResult> SendEmailAsync(ApplicationUser user, string returnUrl, string empleadoNombre, string pwdInic)
i will return my JsonResult
ResponseJson response = new ResponseJson();
response.success = true;
response.message = "Operación exitosa";
return new JsonResult( response);
to read the result returned from my SendEmail method
JsonResult emailSend = await SendEmailAsync(user, returnUrl, empleadoNombre, pwdInic);
ResponseJson response = new ResponseJson();
try
{
string json = JsonConvert.SerializeObject(emailSend.Value);
response = JsonConvert.DeserializeObject<ResponseJson>(json);
}
catch(Exception e)
{
}
I'm using this code to return an object content, but I would like to cache the response adding the Cache-Control headers.
[AllowAnonymous]
[Route("GetPublicContent")]
[HttpGet]
public IHttpActionResult GetPublicContent([FromUri]UpdateContentDto dto)
{
if (dto == null)
return BadRequest();
var content = _contentService.GetPublicContent(dto);
if (content == null)
return BadRequest();
return new Ok(content);
}
Just that! Thanks!!
Make a new class that inherits from OkNegotiatedContentResult<T>:
public class CachedOkResult<T> : OkNegotiatedContentResult<T>
{
public CachedOkResult(T content, TimeSpan howLong, ApiController controller) : base(content, controller)
{
HowLong = howLong;
}
public CachedOkResult(T content, IContentNegotiator contentNegotiator, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
: base(content, contentNegotiator, request, formatters) { }
public TimeSpan HowLong { get; private set; }
public override async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await base.ExecuteAsync(cancellationToken);
response.Headers.CacheControl = new CacheControlHeaderValue() {
Public = false,
MaxAge = HowLong
};
return response;
}
}
To use this in your controller, just return a new instance of the CachedOkResult class:
public async Task<IHttpActionResult> GetSomething(string id)
{
var value = await GetAsyncResult(id);
// cache result for 60 seconds
return new CachedOkResult<string>(value, TimeSpan.FromSeconds(60), this);
}
The headers will come across the wire like this:
Cache-Control:max-age=60
Content-Length:551
Content-Type:application/json; charset=utf-8
... other headers snipped ...
You can set it like this
public HttpResponseMessage GetFoo(int id) {
var foo = _FooRepository.GetFoo(id);
var response = Request.CreateResponse(HttpStatusCode.OK, foo);
response.Headers.CacheControl = new CacheControlHeaderValue()
{
Public = true,
MaxAge = new TimeSpan(1, 0, 0, 0)
};
return response;
}
Update
Or try this question
I am using ASP.NET Web API. I want to download a PDF with C# from the API (that the API generates).
Can I just have the API return a byte[]? and for the C# application can I just do:
byte[] pdf = client.DownloadData("urlToAPI");?
and
File.WriteAllBytes()?
Better to return HttpResponseMessage with StreamContent inside of it.
Here is example:
public HttpResponseMessage GetFile(string id)
{
if (String.IsNullOrEmpty(id))
return Request.CreateResponse(HttpStatusCode.BadRequest);
string fileName;
string localFilePath;
int fileSize;
localFilePath = getFileFromID(id, out fileName, out fileSize);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}
UPDATE from comment by patridge:
Should anyone else get here looking to send out a response from a byte array instead of an actual file, you're going to want to use new ByteArrayContent(someData) instead of StreamContent (see here).
I made the follow action:
[HttpGet]
[Route("api/DownloadPdfFile/{id}")]
public HttpResponseMessage DownloadPdfFile(long id)
{
HttpResponseMessage result = null;
try
{
SQL.File file = db.Files.Where(b => b.ID == id).SingleOrDefault();
if (file == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = Convert.FromBase64String(file.pdfBase64);
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = file.name + ".pdf";
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
Just a note for .Net Core: We can use the FileContentResult and set the contentType to application/octet-stream if we want to send the raw bytes. Example:
[HttpGet("{id}")]
public IActionResult GetDocumentBytes(int id)
{
byte[] byteArray = GetDocumentByteArray(id);
return new FileContentResult(byteArray, "application/octet-stream");
}
Example with IHttpActionResult in ApiController.
[HttpGet]
[Route("file/{id}/")]
public IHttpActionResult GetFileForCustomer(int id)
{
if (id == 0)
return BadRequest();
var file = GetFile(id);
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK);
responseMsg.Content = new ByteArrayContent(file.SomeData);
responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response = ResponseMessage(responseMsg);
return response;
}
If you don't want to download the PDF and use a browsers built in PDF viewer instead remove the following two lines:
responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
You Can try , HttpClient for Download file from another side and same time you can pass as File Result
[HttpGet]
[Route("api/getFile")]
public async Task<FileResult> GetFile(string Param1,string Param2)
{
try
{
Stream stream = null;
string strURL = #"File URL";
HttpClient client = new HttpClient();
HttpResponseMessage httpResponse = await client.GetAsync(strURL);
Stream streamToReadFrom = await httpResponse.Content.ReadAsStreamAsync();
return File(streamToReadFrom, "{MIME TYPE}");
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
}
I've been wondering if there was a simple way to download a file in a more ... "generic" way. I came up with this.
It's a simple ActionResult that will allow you to download a file from a controller call that returns an IHttpActionResult.
The file is stored in the byte[] Content. You can turn it into a stream if needs be.
I used this to return files stored in a database's varbinary column.
public class FileHttpActionResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string FileName { get; set; }
public string MediaType { get; set; }
public HttpStatusCode StatusCode { get; set; }
public byte[] Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = new HttpResponseMessage(StatusCode);
response.StatusCode = StatusCode;
response.Content = new StreamContent(new MemoryStream(Content));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = FileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(MediaType);
return Task.FromResult(response);
}
}
Another way to download file is to write the stream content to the response's body directly:
[HttpGet("pdfstream/{id}")]
public async Task GetFile(long id)
{
var stream = GetStream(id);
Response.StatusCode = (int)HttpStatusCode.OK;
Response.Headers.Add( HeaderNames.ContentDisposition, $"attachment; filename=\"{Guid.NewGuid()}.pdf\"" );
Response.Headers.Add( HeaderNames.ContentType, "application/pdf" );
await stream.CopyToAsync(Response.Body);
await Response.Body.FlushAsync();
}