I need to write a Web API method that return result as CSS plain text and not the default XML or JSON, Is there a specific provider that I need to use?
I tried using the ContentResult class (http://msdn.microsoft.com/en-us/library/system.web.mvc.contentresult(v=vs.108).aspx) but no luck.
Thanks
You should bypass the content negotiation which means that you should return a new instance of HttpResponseMessage directly and set the content and the content type yourself:
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(".hiddenView { display: none; }", Encoding.UTF8, "text/css")
};
Using the answers here as inspiration. You should be able to do something as simple as this:
public HttpResponseMessage Get()
{
string css = #"h1.basic {font-size: 1.3em;padding: 5px;color: #abcdef;background: #123456;border-bottom: 3px solid #123456;margin: 0 0 4px 0;text-align: center;}";
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent(css, Encoding.UTF8, "text/css");
return response;
}
Can you return a HttpResponseMessage, get the file and just return the stream? Something like this seems to work....
public HttpResponseMessage Get(int id)
{
var dir = HttpContext.Current.Server.MapPath("~/content/site.css"); //location of the template file
var stream = new FileStream(dir, FileMode.Open);
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StreamContent(stream)
};
return response;
}
Although I would add some error checking in there if the file doesn't exist etc....
And just to pile on for fun, here's a version that would work under self-host too assuming you store the .css as an embedded file that sits in the same folder as the controller. Storing it in a file in your solution is nice because you get all the VS intellisense. And I added a bit of caching because chances are this resource isn't going to change much.
public HttpResponseMessage Get(int id)
{
var stream = GetType().Assembly.GetManifestResourceStream(GetType(),"site.css");
var cacheControlHeader = new CacheControlHeaderValue { MaxAge= new TimeSpan(1,0,0)};
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
CacheControl = cacheControlHeader,
Content = new StreamContent(stream, Encoding.UTF8, "text/css" )
};
return response;
}
For anyone using AspNet Core WebApi you can simply do it like this
[HttpGet("custom.css")]
public IActionResult GetCustomCss()
{
var customCss = ".my-class { color: #fff }";
return Content(customCss, "text/css");
}
Related
I am facing one error sometimes, when I try get a picture from user gallery.
I get the picture in a Stream object, convert it to a base64 and I send it using a post function.
Sometimes The program says that the image path is big and, because of that, its not possible send the url.
I heard that its cause the image size but I am not sure about it...
Does someone know what really causes a Big base64 string? How can I solve that?
You could follow something similar to this:
http://jamessdixon.wordpress.com/2013/10/01/handling-images-in-webapi/
Maybe you need make some change in your web api like this:
[HttpPost]
public HttpResponseMessage UploadImage(int ID)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
if (Request.Content.IsMimeMultipartContent())
{
Request.Content.LoadIntoBufferAsync().Wait();
Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ContinueWith((task) =>
{
MultipartMemoryStreamProvider provider = task.Result;
foreach (HttpContent content in provider.Contents)
{
Stream stream = content.ReadAsStreamAsync().Result;
Image image = Image.FromStream(stream);
var testName = content.Headers.ContentDisposition.Name;
String filePath = HostingEnvironment.MapPath("~/Content/");
String fullPath = Path.Combine(filePath, ID.ToString()+".jpg");
image.Save(fullPath);
}
});
return result;
}
else
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
}
}
After making sure your api web works well you should change from Stream to byte[]
In your Xamarin code try this:
public async Task PostItem(String Controller, String Method, int ID, byte[] item)
{
using (var client = CreateClient ()) {
var da = new ByteArrayContent(item);
try{
var multi = new MultipartContent();
multi.Add(da);
var response = await client.PostAsync (Controller + "/" +Method + "/?ID=" +ID, multi);
}catch(Exception ex)
{
Console.Write(ex.Message);
}
}
}
For more infomation see MultipartContent class documentation
I have the following controller method which returns a byte array.
public async Task<HttpResponseMessage> Get()
{
var model = new byte[] { 1, 2, 3 };
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(new MemoryStream(model));
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
I think this is an older way of implementing this functionality with web api. Is there a more "modern" version?
For example, is returning a Task<IHttpActionResult> the preferred way now? And if so, what would be the code to return the byte array from above?
As the comment pointed out. I dont think there is a new way to do this. But if you would like to return an IHttpActionResult instead, there is a base method that returns a ResponseMessageResult:
public IHttpActionResult Get()
{
var model = new byte[] { 1, 2, 3 };
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream(model))
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return ResponseMessage(result);
}
Also, to return binary data in AspNetCore WebApi2 if anyone needs it:
[Route("api/v1/export/excel")]
[HttpGet]
public IActionResult GetAsExcel()
{
var exportStream = new MemoryStream();
_exportService.ExportAllToExcel(exportStream);
// Rewind the stream before we send it.
exportStream.Position = 0;
return new FileStreamResult(exportStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
Lets say I want a screen scraper that doesn't care if you pass it an HTML page, url that goes to an XML Document, or a Url that goes to a text file.
examples:
http://tonto.eia.doe.gov/oog/info/wohdp/dslpriwk.txt
http://google.com
This will work if the page is HTML or a text file:
public class ScreenScrapingService : IScreenScrapingService
{
public XDocument Scrape(string url)
{
var scraper = new HtmlWeb();
var stringWriter = new StringWriter();
var xml = new XmlTextWriter(stringWriter);
scraper.LoadHtmlAsXml(url, xml);
var text = stringWriter.ToString();
return XDocument.Parse(text);
}
}
However; if it is an XML file such as:
http://www.eia.gov/petroleum/gasdiesel/includes/gas_diesel_rss.xml
[Test]
public void Scrape_ShouldScrapeSomething()
{
//arrange
var sut = new ScreenScrapingService();
//act
var result = sut.Scrape("http://www.eia.gov/petroleum/gasdiesel/includes/gas_diesel_rss.xml");
//assert
}
Then I get the error:
An exception of type 'System.Xml.XmlException' occurred in System.Xml.dll but was not handled in user code
Is it possible to write this so that it doesn't care what the URL ultimately is?
to get the exact exception on visual studio CTR+ALT+E and enable CommonLanguageRunTimeExceptions, it seems like LoadHtmlAsXml expects html, so probably your best bet is to use a WebClient.DownloadString(url) and HtmlDocument with property OptionOutputAsXml set to true as the following, when that fails catch it
public XDocument Scrape(string url)
{
var wc = new WebClient();
var htmlorxml = wc.DownloadString(url);
var doc = new HtmlDocument() { OptionOutputAsXml = true};
var stringWriter = new StringWriter();
doc.Save(stringWriter);
try
{
return XDocument.Parse(stringWriter.ToString());
}
catch
{
//it only gets here when the string is xml already
try
{
return XDocument.Parse(htmlorxml);
}
catch
{
return null;
}
}
}
We are using asp.net web api in our application, in that we are trying to return the response with content-type with text/plain format but We are unable to succeeded. Same thing we tried with ASP.NET MVC it is working fine could you please provide me equivalent solution in Web API.
Please find below for the function implemented in ASP.NET MVC
public JsonResult FileUpload(HttpPostedFileBase file)
{
string extension = System.IO.Path.GetExtension(file.FileName);
string bufferData = string.Empty;
if (file != null)
{
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
byte[] array = ms.GetBuffer();
var appendInfo = "data:image/" + extension + ";base64,";
bufferData = appendInfo + Convert.ToBase64String(array);
}
}
var result = new
{
Data = bufferData
};
return Json(result,"text/plain");
}
Could you please suggest same implementation in WebAPI.
Thanks,
Bhagat
Web Api does the JSON work for you, so you can simplify your code handling on the endpoint. By default, you need to make changes in your WebApiConfig.cs for everything to work nicely. I've modified your method below:
public HttpResponseMessage FileUpload(HttpPostedFileBase file) {
var result = new HttpResponseMessage(HttpStatusCode.NotFound);
var bufferData = string.Empty;
try
{
if (file != null)
{
var extension = System.IO.Path.GetExtension(file.FileName);
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
var array = ms.GetBuffer();
var appendInfo = "data:image/" + extension + ";base64,";
bufferData = appendInfo + Convert.ToBase64String(array);
result.StatusCode = HttpStatusCode.OK;
// Set Headers and Content here
result.Content = bufferData;
}
}
}
catch(IOException ex)
{
// Handle IO Exception
}
return result
}
The changes you need to make in your WebApiConfig.cs could look like this:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}",
defaults: null,
constraints: new { action = #"\D+" }
);
// This makes the response default into JSON instead of XML
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
As a note, the very fastest fix you can make to your code would be to do this, but I don't recommend returning strings.
public string FileUpload(HttpPostedFileBase file) {
var result = new HttpResponseMessage(HttpStatusCode.NotFound);
var bufferData = string.Empty;
if (file != null)
{
var extension = System.IO.Path.GetExtension(file.FileName);
using (MemoryStream ms = new MemoryStream())
{
file.InputStream.CopyTo(ms);
var array = ms.GetBuffer();
var appendInfo = "data:image/" + extension + ";base64,";
bufferData = appendInfo + Convert.ToBase64String(array);
return bufferData;
}
}
// If you get here and have not returned,
// something went wrong and you should return an Empty
return String.Empty;
}
Good luck - there's lots of ways of handling files and file returns, so I want to assume you don't have some special return value on your handling.
I've got a partial view, i'm trying to use ITextSharp to convert the html to pdf. How can I convert the html to string so I can use ItextSharps HtmlParser?
I've tried something like this with no luck...any ideas?:
var contents = System.IO.File.ReadAllText(Url.Action("myPartial", "myController", new { id = 1 }, "http"));
I have created a special ViewResult class that you can return as the result of an Action.
You can see the code on bitbucket (look at the PdfFromHtmlResult class).
So what it basically does is:
Render the view through the Razor engine (or any other registered engine) to Html
Give the html to iTextSharp
return the pdf as the ViewResult (with correct mimetype, etc).
My ViewResult class looks like:
public class PdfFromHtmlResult : ViewResult {
public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
if (string.IsNullOrEmpty(this.ViewName)) {
this.ViewName = context.RouteData.GetRequiredString("action");
}
if (this.View == null) {
this.View = this.FindView(context).View;
}
// First get the html from the Html view
using (var writer = new StringWriter()) {
var vwContext = new ViewContext(context, this.View, this.ViewData, this.TempData, writer);
this.View.Render(vwContext, writer);
// Convert to pdf
var response = context.HttpContext.Response;
using (var pdfStream = new MemoryStream()) {
var pdfDoc = new Document();
var pdfWriter = PdfWriter.GetInstance(pdfDoc, pdfStream);
pdfDoc.Open();
using (var htmlRdr = new StringReader(writer.ToString())) {
var parsed = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(htmlRdr, null);
foreach (var parsedElement in parsed) {
pdfDoc.Add(parsedElement);
}
}
pdfDoc.Close();
response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", this.ViewName + ".pdf");
byte[] pdfBytes = pdfStream.ToArray();
response.OutputStream.Write(pdfBytes, 0, pdfBytes.Length);
}
}
}
}
With the correct extension methods (see BitBucket), etc, the code in my controller is something like:
public ActionResult MyPdf(int id) {
var myModel = findDataWithID(id);
// this assumes there is a MyPdf.cshtml/MyPdf.aspx as the view
return this.PdfFromHtml(myModel);
}
Note: Your method does not work, because you will retrieve the Html on the server, thereby you loose all cookies (=session information) that are stored on the client.