Saving HTML report by showing Save As dialog - asp.net-mvc

I want to show a Save As dialog box to user in my MVC application and allow him to save some HTML report in the format of pdf or word. For doing this, do I need to play with File stream and IO functions at server side? Or is it possible at JQuery level itself?
I found some references on web like adding a response header Content-Disposition, but not getting how to apply it. Can you please suggest some options?

You must create a descendant from ActionResult that plays with output the desired way.
This is a class of mine I created to implement a "Save as Excel" feature:
public class ExcelResult : ActionResult
{
private string _fileName;
private IQueryable _rows;
private string[] _headers = null;
private string _data;
private TableStyle _tableStyle;
private TableItemStyle _headerStyle;
private TableItemStyle _itemStyle;
public string FileName
{
get { return _fileName; }
}
public IQueryable Rows
{
get { return _rows; }
}
public ExcelResult(string data, string fileName)
{
_fileName = fileName;
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
WriteFile(_fileName, "application/ms-excel", _data);
}
private string ReplaceSpecialCharacters(string value)
{
value = value.Replace("’", "'");
value = value.Replace("“", "\"");
value = value.Replace("”", "\"");
value = value.Replace("–", "-");
value = value.Replace("…", "...");
return value;
}
private void WriteFile(string fileName, string contentType, string content)
{
HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
context.Response.Charset = "";
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.ContentType = contentType;
context.Response.Write(content);
context.Response.End();
}
}
You can use this example to generate HTML for word. PDF are a different matter, tho'.

Related

How to save and read Cookie in Asp.net Mvc

I save my cookie as the following code:
public static void SetCookie(string key, string value, int expireDay = 1)
{
var cookie = new HttpCookie(key , value);
cookie.Expires = DateTime.Now.AddDays(expireDay);
HttpContext.Current.Response.Cookies.Add(cookie);
}
The cookie values when stored are as follows:
Read Cookie:
public static string GetCookie(string key)
{
string value = string.Empty;
var cookie = HttpContext.Current.Request.Cookies[key];
if (cookie != null)
{
if (string.IsNullOrWhiteSpace(cookie.Value))
{
return value;
}
value = cookie.Value;
}
return value;
}
The problem is that when reading the cookie, all the values are empty according to the image below:
The maximum size of a cookie is 4kb.
Actually you should read cookies from request header; not response!
The problem is here: HttpContext.Current.Response.Cookies.AllKeys.Contains(key).
You need to read it from the request. And write the changes to the response.
Here's a simpler working example, that simply prints "Hey!", and appends an exclamation on each GET:
public class IndexModel : PageModel
{
public string CookieValue = "Hey!";
private const string COOKIE_KEY = "HEY_COOKIE";
public void OnGet()
{
Request.Cookies.TryGetValue(COOKIE_KEY, out string? actualValue);
if (actualValue is not null) CookieValue = actualValue + "!";
// Only required since we're changing the cookie
// TODO: set the right cookie options
Response.Cookies.Append(COOKIE_KEY, CookieValue, new CookieOptions { });
}
}
#page
#model IndexModel
<h1>#Model.CookieValue</h1>
Also, while debugging things over HTTP, it's useful to also look at Chrome's network tab.
Your problem is that you used HttpContext.Current.Response. Instead of this, you should declare a parameter in the SetCookie method like this: HttpContext context, then in the controller, when you call the method, you have to send HttpContext controller property as an argument.
public static void SetCookie(HttpContext context, string key, string value, int expireDay = 1)
{
var cookie = new HttpCookie(key , value);
cookie.Expires = DateTime.Now.AddDays(expireDay);
context.Response.Cookies.Add(cookie);
}
In the controller:
SetCookie(HttpContext, yourKey,yourValue)
You also should change your GetCookie method like this:
public static string GetCookie(HttpContext context,string key)
{
string value = string.Empty;
var cookie = context.Request.Cookies[key];
if (cookie != null)
{
if (string.IsNullOrWhiteSpace(cookie.Value))
{
return value;
}
value = cookie.Value;
}
return value;
}

Unable to update row of tableView after connecting to a url

I am building a download manager
Here I have shown a test code which tries to update fileNameColumn of a row of tableView but it is not being updated after I connect to url
To be specific, here fileName remains hello1 and it doesnt get updated to hello2. Yhy's that so?
Main.java :
public static TableView<DownloadEntry> downloadsTable;
public TableColumn<DownloadEntry, String> fileNameColumn;
public void initialize(URL location, ResourceBundle resources) {
downloadsTable = new TableView<DownloadEntry>();
fileNameColumn = new TableColumn<>("File Name");
fileNameColumn.setCellValueFactory(new PropertyValueFactory<>("fileName"));
executor = Executors.newFixedThreadPool(4);
}
public void addDownloadButtonClicked() {
try{
String urlText = urlTextBox.getText();
DownloadEntry task = new DownloadEntry(new URL(urlText));
downloadsTable.getItems().add(task);
executor.execute(task);
}
catch(Exception e) {
System.out.println("addDownloadButtonClicked: " + e);
}
}
DownloadEntry.java:
public class DownloadEntry extends Task<Void> {
public SimpleStringProperty fileName;
public URL url;
//Constructor
public DownloadEntry(URL ur) throws Exception{
fileName = new SimpleStringProperty("hello");
url = ur;
}
#Override
protected Void call() {
try {
HttpURLConnection connect=(HttpURLConnection)url.openConnection();
fileName.set("hello1");
connect.connect();
fileName.set("hello2");
}
catch(Exception E) {
this.updateMessage("Error");
E.printStackTrace();
}
return null;
}
public String getFileName() {
return fileName.get();
}
public void setFileName(String fileName) {
this.fileName = new SimpleStringProperty(fileName);
}
}
Please tell if you need more details..
Your model is incorrectly implemented. The setFileName method should be
public void setFileName(String fileName) {
this.fileName.set(fileName);
}
(The problem with your implementation is that the table is still observing the old property, not the new one you create.)
You will also need to provide a "property accessor" method:
public StringProperty fileNameProperty() {
return fileName ;
}
which will allow the table to properly bind to the property (so that it "knows" when its value changes).

How to return json date from MVC4 controller in ISO format

I tried tro return date in ISO format using Json.Net from ASP.NET MVC4 controller
public JsonResult Sales() {
var saleList = new List<Sale>();
...
var str = JsonConvert.SerializeObject(saleList);
return Json(str, JsonRequestBehavior.AllowGet);
}
public class Sale
{
public DateTime saledate { get; set; }
...
}
But it returns whole object json notation as single string.
How to return date in ISO format as json object ?
You can do it with ServiceStack JSON serializer but first you have to integrate it to ASP.NET MVC.
After installing the package, configure DateTime serialization in application start:
JsConfig.DateHandler = JsonDateHandler.ISO8601;
Create an ActionResult type for JSON content:
public class CustomJsonResult : ActionResult
{
private readonly object _data;
private readonly string _content;
private readonly Encoding _encoding;
public CustomJsonResult(object data) : this(data, null, null) { }
public CustomJsonResult(object data, string content) : this(data, content, null) { }
public CustomJsonResult(object data, Encoding encoding) : this(data, null, encoding) { }
public CustomJsonResult(object data, string content, Encoding encoding)
{
_data = data;
_content = content;
_encoding = encoding;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = string.IsNullOrEmpty(_content) ? "application/json" : _content;
if (_encoding != null)
{
response.ContentEncoding = _encoding;
}
response.Write(JsonSerializer.SerializeToString(_data));
}
}
Then you can add these methods to a base controller:
protected CustomJsonResult CustomJson(object data)
{
return new CustomJsonResult(data);
}
protected CustomJsonResult CustomJson(object data, string content)
{
return new CustomJsonResult(data, content);
}
protected CustomJsonResult CustomJson(object data, Encoding encoding)
{
return new CustomJsonResult(data, encoding);
}
protected CustomJsonResult CustomJson(object data, string content, Encoding encoding)
{
return new CustomJsonResult(data, content, encoding);
}
At last you can return the result like this:
return CustomJson(saleList);
You can set settings when using an overload to SerializeObject that takes an JsonSerializerSettings parameter:
public static string SerializeObject(
Object value,
JsonSerializerSettings settings
)
The JsonSerializerSettings have a property called DateFormatHandlingused to distinguish between Microsoft Format and ISO format.
You could also use a custom converter in JSON.NET. Custom Converters can be applied using the CustomConverter attribute.
An example can be found in the JSON.NET documentation: http://james.newtonking.com/json/help/index.html
I would prefer the first possibility.

Download file in Struts 2 using annotation

I would like to ask if anyone can help me with an example to download a file using Struts 2 annotation
I have tried this in my action class
public class MyClass {
private InputStream fileInputStream;
private String fileName;
#Override
#Action(AbstractBasisAction.VIEW)
public String view() {
System.out.println("HoursCycleDownloadFrameAction: view");
super.view();
return SUCCESS;
}
public InputStream getFileInputStream() {
return fileInputStream;
}
#Action(value = "downloadFile", results = { #Result(name = "success", type = "stream", params = { "contentType", "application/octet-stream", "inputName", "fileInputStream", "contentDisposition", "filename=\"${fileName}\"", "bufferSize", "1024" }) })
public String downloadFile() throws Exception {
fileName = "license.txt";
fileInputStream = new FileInputStream(new File("C:\\", fileName));
return SUCCESS;
}
}
and this is what my page contains
<s:url id="fileInputStream" namespace="/myClass" action="downloadFile" ></s:url>
Download file - <s:a href="%{fileInputStream}">lisence.txt</s:a>
but the problem now is that it downloads the file with the action method name. Means that the file name is downloadFile.action. Can anyone help me with that?
1) if it is a .txt file, "contentType", "application/octet-stream"
should instead be "contentType", "plain/text";
2) you need a getter for your private String fileName; variable;
3) "contentDisposition", "filename=\"${fileName}\"" should contains extension, and eventually inline (default, open in browser) or attachment (ask if donwload or open with client application), for example
"contentDisposition", "attachment; filename=\"${fileName}.txt\""

How to receive XmlDocument in MVC 4 Web Api?

I am posting XmlDocument to ApiController (from windows service, service is working fine, it is posting correct, i used it in wcf web api), but xml is always null, what am i doing wrong?
I can post some class, such in tutotials, or Get any data and everything will be ok, but i can't post XmlDocument.
public class XmlController : ApiController
{
public void PostXml(XmlDocument xml)
{
// code
}
}
i follow the solution given by #Rhot but somehow it doesn't work so i edit like below which work for me:
public class XmlMediaTypeFormatter : MediaTypeFormatter
{
public XmlMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml"));
}
public override bool CanReadType(Type type)
{
return type == typeof(XDocument);
}
public override bool CanWriteType(Type type)
{
return type == typeof(XDocument);
}
public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger)
{
var reader = new StreamReader(stream);
string value = reader.ReadToEnd();
var tcs = new TaskCompletionSource<object>();
try
{
var xmlDoc = XDocument.Parse(value);
tcs.SetResult(xmlDoc);
}
catch (Exception ex)
{
//disable the exception and create custome error
//tcs.SetException(ex);
var xml = new XDocument(
new XElement("Error",
new XElement("Message", "An error has occurred."),
new XElement("ExceptionMessage", ex.Message)
));
tcs.SetResult(xml);
}
return tcs.Task;
}
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
var writer = new StreamWriter(stream);
writer.Write(((XDocument)value).ToString());
writer.Flush();
var tcs = new TaskCompletionSource<object>();
tcs.SetResult(null);
return tcs.Task;
}
}
register to global.asax:
GlobalConfiguration.Configuration.Formatters.Insert(0, new XmlMediaTypeFormatter());
and below my WebAPI Controller:
public HttpResponseMessage Post(XDocument xml)
{
return Request.CreateResponse(HttpStatusCode.OK, xml);
}
I've found a solution:
We need to use inheritance to inherit MediaTypeFormatter
public class XmlMediaTypeFormatter : MediaTypeFormatter
{
public XmlMediaTypeFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
}
public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type, Stream stream,
HttpContentHeaders contentHeaders,
IFormatterLogger formatterLogger)
{
var taskCompletionSource = new TaskCompletionSource<object>();
try
{
var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(s);
taskCompletionSource.SetResult(xmlDoc);
}
catch (Exception e)
{
taskCompletionSource.SetException(e);
}
return taskCompletionSource.Task;
}
public override bool CanReadType(Type type)
{
return type == typeof(XmlDocument);
}
public override bool CanWriteType(Type type)
{
return false;
}
}
Then register it in Global.asax:
GlobalConfiguration.Configuration.Formatters.Insert(0, new XmlMediaTypeFormatter());
Controller:
public HttpResponseMessage PostXml([FromBody] XmlDocument xml)
{//code...}
Is PostXml supposed to be an action on a controller? If so you should mark your controller action as accepting an HttpPost. From there I would modify the action to work as follows:
[HttpPost]
public ActionResult PostXml(HttpPostedFileBase xml)
{
// code
}
If you are still have trouble accepting the posted files, fire up the debugger and inspect the Request files collection: http://msdn.microsoft.com/en-us/library/system.web.httprequest.files.aspx

Resources