Web Api HttpResponseMessage not returning file download - excel

I am currently doing a POST to a Web Api method and am posting an array of objects. When I get to the method, my parameters are resolved properly, and I make a call to the DB and return a list of records.
I then take those records and convert them to a MemoryStream to be downloaded by the browser as an Excel spreasheet. From there, I create an HttpResponseMessage object and set properties so that the browser will recognize this response as a spreadsheet.
public HttpResponseMessage ExportSpreadsheet([FromBody]CustomWrapperClass request){
var result = new HttpResponseMessage();
var recordsFromDB = _service.GetRecords(request);
MemoryStream export = recordsFromDB.ToExcel(); //custom ToExcel() extension method
result.Content = new StreamContent(export);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.Name = "formName";
result.Content.Headers.ContentDisposition.FileName = "test.xlsx";
return result;
}
Instead of seeing the spreadsheet being downloaded, nothing seems to happen. When I check the developer tools (for any browser), I see the Response Headers below while the Response tab just shows binary data. Does anyone know what I might be missing here?

How are you doing your POST? It sounds like you might be trying to this via a javascript AJAX call, which cannot be done (https://stackoverflow.com/a/9970672/405180).
I would instead make this a GET request for starters, and use something like window.location="download.action?para1=value1....". Generally web api Post requests are made to create a file/entry, not retrieve one.
Alternatively, you could use a HTML Form with hidden elements corresponding to your query parameters, and use javascript to submit the form.

Related

DocuSign API Javascript SDK - getDocument returns string

I am trying to call the api endpoint getDocument via Node, and am expecting a Buffer to be returned, however, it is returning a string. Even when I pass in different values for the encoding optional parameter, the data returned is always the same.
When I tested the same endpoint in C#, a MemoryStream is returned which is expected.
My code is as follows:
const document = await envelopesApi.getDocument(accountId, envelopeId, '1')
Where 1 is the documentId (page 1).
The contents of document looks like %PDF-1.5\n%ûüýþ\n%Writing objects... and so on
I am then trying to save this to a file:
fs.writeFileSync('test.pdf', Buffer.from(documentContent))
With no success. How do I get the api response and save it to a file for viewing?
Yes, this is correct, you will have to use the correct mime type for PDF (in this case) in order to show this file in the browser.
You can find a node.JS code example that shows you how to do this.
But the most important part in your case would be this line:
mimetype = "application/pdf";

Dart redstone web application

Let's say I configure redstone as follows
#app.Route("/raw/user/:id", methods: const [app.GET])
getRawUser(int id) => json_about_user_id;
When I run the server and go to /raw/user/10 I get raw json data in a form of a string.
Now I would like to be able to go to, say, /user/10 and get a nice representation of this json I get from /raw/user/10.
Solutions that come to my mind are as follows:
First
create web/user/user.html and web/user/user.dart, configure the latter to run when index.html is accessed
in user.dart monitor query parameters (user.dart?id=10), make appropriate requests and present everything in user.html, i.e.
var uri = Uri.parse( window.location.href );
String id = uri.queryParameters['id'];
new HttpRequest().getString(new Uri.http(SERVER,'/raw/user/${id}').toString() ).then( presentation )
A downside of this solution is that I do not achieve /user/10-like urls at all.
Another way is to additionally configure redstone as follows:
#app.Route("/user/:id", methods: const [app.GET])
getUser(int id) => app.redirect('/person/index.html?id=${id}');
in this case at least urls like "/user/10" are allowed, but this simply does not work.
How would I do that correctly? Example of a web app on redstone's git is, to my mind, cryptic and involved.
I am not sure whether this have to be explained with connection to redstone or dart only, but I cannot find anything related.
I guess you are trying to generate html files in the server with a template engine. Redstone was designed to mainly build services, so it doesn't have a built-in template engine, but you can use any engine available on pub, such as mustache. Although, if you use Polymer, AngularDart or other frameowrk which implements a client-side template system, you don't need to generate html files in the server.
Moreover, if you want to reuse other services, you can just call them directly, for example:
#app.Route("/raw/user/:id")
getRawUser(int id) => json_about_user_id;
#app.Route("/user/:id")
getUser(int id) {
var json = getRawUser();
...
}
Redstone v0.6 (still in alpha) also includes a new foward() function, which you can use to dispatch a request internally, although, the response is received as a shelf.Response object, so you have to read it:
#app.Route("/user/:id")
getUser(int id) async {
var resp = await chain.forward("/raw/user/$id");
var json = await resp.readAsString();
...
}
Edit:
To serve static files, like html files and dart scripts which are executed in the browser, you can use the shelf_static middleware. See here for a complete Redstone + Polymer example (shelf_static is configured in the bin/server.dart file).

Web API action filter content can't be read

Related question: Web API action parameter is intermittently null and http://social.msdn.microsoft.com/Forums/vstudio/en-US/25753b53-95b3-4252-b034-7e086341ad20/web-api-action-parameter-is-intermittently-null
Hi!
I'm creating a ActionFilterAttribute in ASP.Net MVC WebAPI 4 so I can apply the attribute in action methods at the controller that we need validation of a token before execute it as the following code:
public class TokenValidationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
//Tried this way
var result = string.Empty;
filterContext.Request.Content.ReadAsStringAsync().ContinueWith((r)=> content = r.Result);
//And this
var result = filterContext.Request.Content.ReadAsStringAsync().Result;
//And this
var bytes = await request.Content.ReadAsByteArrayAsync().Result;
var str = System.Text.Encoding.UTF8.GetString(bytes);
//omit the other code that use this string below here for simplicity
}
}
I'm trying to read the content as string. Tried the 3 ways as stated in this code, and all of them return empty. I know that in WebApi I can read only once the body content of the request, so I'm commenting everything else in the code, and trying to get it run to see if I'm getting a result. The point is, the client and even the Fiddler, reports the 315 of the content length of the request. The same size is getting on the server content header as well but, when we try read the content, it is empty.
If I remove the attribute and make the same request, the controller is called well, and the deserialization of Json happens flawless. If I put the attribute, all I get is a empty string from the content. It happens ALWAYS. Not intermittent as the related questions state.
What am I doing wrong? Keep in mind that I'm using ActionFilter instead of DelegatingHandler because only selected actions requires the token validation prior to execution.
Thanks for help! I really appreciate it.
Regards...
Gutemberg
By default the buffer policy for Web Host(IIS) scenarios is that the incoming request's stream is always buffered. You can take a look at System.Web.Http.WebHost.WebHostBufferPolicySelector. Now as you have figured, Web Api's formatters will consume the stream and will not try to rewind it back. This is on purpose because one could change the buffer policy to make the incoming request's stream to be non-buffered in which case the rewinding would fail.
So in your case, since you know that the request is going to be always buffered, you could get hold of the incoming stream like below and rewind it.
Stream reqStream = await request.Content.ReadAsStreamAsync();
if(reqStream.CanSeek)
{
reqStream.Position = 0;
}
//now try to read the content as string
string data = await request.Content.ReadAsStringAsync();

Monotouch/iPhone - Call to HttpWebRequest.GetRequestStream() connects to server when HTTP Method is DELETE

My Scenario:
I am using Monotouch for iOS to create an iPhone app. I am calling ASP.NEt MVC 4 Web API based http services to login/log off. For Login, i use the POST webmethod and all's well. For Logoff, i am calling the Delete web method. I want to pass JSON data (serialized complex data) to the Delete call. If i pass simple data like a single string parameter as part of the URL itself, then all's well i.e. Delete does work! In order to pass the complex Json Data, here's my call (i have adjusted code to make it simple by showing just one parameter - UserName being sent via JSON):
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost/module/api/session/");
req.ContentType = "application/json";
req.CookieContainer = jar;
req.Method = "Delete";
using (var streamWrite = new StreamWriter(req.GetRequestStream()))
{
string jSON = "{\"UserName\":\"" + "someone" + "\"}";
streamWrite.Write(jSON);
streamWrite.Close();
}
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
on the server, the Delete method looks has this definition:
public void Delete(Credentials user)
where Credentials is a complex type.
Now, here's the issue!
The above code, gets into the Delete method on the server as soon as it hits:
req.GetRequestStream()
And hence the parameter sent to the Delete method ends up being null
And here's the weird part:
If i use the exact same code using a test VS 2010 windows application, even the above code works...i.e it does not call Delete until req.GetResponse() is called! And in this scenario, the parameter to the Delete method is a valid object!
QUESTION
Any ideas or Is this a bug with Monotouch, if so, any workaround?
NOTE:
if i change the Delete definition to public void Delete(string userName)
and instead of json, if i pass the parameter as part of the url itself, all's well. But like i said this is just a simplified example to illustrate my issue. Any help is appreciated!!!
This seems to be ill-defined. See this question for more details: Is an entity body allowed for an HTTP DELETE request?
In general MonoTouch (based on Mono) will try to be feature/bug compatible with the Microsoft .NET framework to ease code portability between platforms.
IOW if MS.NET ignores the body of a DELETE method then so will MonoTouch. If the behaviour differs then a bug report should be filled at http://bugzilla.xamarin.com

Kohana 3, serve image stored in a database

I had this working on kohana 2, but in kohana 3 it doesn't.
To serve an image stored as BLOB in a database, I did the following:
1- A controller to which I request what image do I want. I connects to the database, using a model of course, and serve the image using a view.
$prod = ORM::factory('product',$idx);
$img = new View('image');
$img->pic = $prod->getImage();
2-The model has a little trick to get this working:
public function getImage()
{
return imagecreatefromstring($this->image);
}
image is the blob column where I store the picture I want to serve.
3- In the view:
I set the content-type header and then serve the image
header('content-type: image/png; charset=UTF-8');
imagepng($pic);
This worked in Kohana 2, but in KO3 it doesn't,
I'm trying to use $response->send_file(), but I'm getting lost
First, you should never send headers with header() unless you're hacking the fw. Ko3.1 nicely separates Request from Response and the latter is the one responsible for response headers / everything else (both of them are written pretty much following the RFC 2616).
Secondly, there is absolutelly no need for a view file in this case, Response::$_body is what the current response object returns.
Response::send_file() returns the response as download, I suppose that's not what you're trying to accomplish?
So, you need something like this (modify to your own needs):
public function action_image($id)
{
$image = ORM::factory('product', $id);
if ( ! $image->loaded()) // ... 404 ?
$this->response
->headers('Content-Type','image/png')
->body($image->image)
->check_cache(NULL, $this->request); // 304 ?
}

Resources