File download of server -generated file from button asp.net mvc - asp.net-mvc

OK, this sounds dumb even to me, but I am clearly having a "bad brain day" and need help.
On a button click, I want to generate a file based on parameters taken from 2 ViewData fields and a checkbox control, and have the file be downloaded/displayed, just as you get with a fixed link.
Most of it is going fine, the controller method passes back a file like so: Return File(filePath, "text/csv") - but then what? How do I connect that to the button and have the file download/open dialog come up?
I feel I am missing something really simple. Just calling the controller via ajax seems to do nothing... the code is called but I see no results
***** EDIT: ******
The following gets me a file automatically downloaded, but with the name "download" - I want to offer the user the choice to open or download, and to set the filename - how do I do that?
serialize = function (obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
var params = {
ID1: '#ViewData("ID1")',
ID2: '#ViewData("ID2")',
flag: getFlag()
};
var actionUrl = ('#Url.Action("ProduceReport", "Report")');
actionUrl += "/?" + serialize(params);
window.open(actionUrl);
* 2nd edit *
Controller code - this produces a file and returns the path. After the call to ProduceReport The file is there on that path, this I have checked. It is used in production to email the file (works fine).
public FileResult ProduceReport(int ID1, int ID2, bool flag = false)
{
var filePath = ExcelReports.ProduceReportExcel(Models.UserInfo.GetCurrentUserID, ID1, ID2, flag);
return File(filePath,"application/vnd.ms-excel");
}

The acceptable compromise that I found, to at least get the file downloaded. I will have to do further research to see if I can print it automatically.
Javascript:
serialize = function (obj) {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
var params = {
ID1: '#ViewData("ID1")',
ID2: '#ViewData("ID2")',
flag: getFlag()
};
var actionUrl = ('#Url.Action("ProduceReport", "Report")');
actionUrl += "/?" + serialize(params);
window.location.href = actionUrl;
Controller: Note 3rd parameter on the File() call
public FileResult ProduceReport(int ID1, int ID2, bool flag = false)
{
var filePath = ExcelReports.ProduceReportExcel(Models.UserInfo.GetCurrentUserID, ID1, ID2, flag);
return File(filePath,"application/vnd.ms-excel",System.IO.Path.GetFileName(filePath));
}

Related

How to get the ID of an inserted record in HANA back to SAPUI5 application?

I got an SAPUI5-application in which I create entries and save them via OData-service. That works, the code for the create operation can be found below. What I have to do now is, I need the ID of the inserted record in HANA back in my application. So what I did I implemented a success handler and thought I would get back this ID in the response from my OData-service. But that is not the case, I get back the same value I provided, in this case 0 since this just a dummy value for the OData-service. I did some research on how to tackle this problem, but none of the approaches worked. So I hope someone of you can help me out or got a hint how to do this. Below the code for create-operation, odata-service and the create.xsjs:
Create-operation in SAPUI5:
this.getOwnerComponent().getModel("Mitarbeiter").create("/ARB", oEntry, {
success: function(oData, response){
console.log(response);
}
});
OData-service:
service {
"MITARBEITERABTEILUNG"."ABTEILUNG" as "ABT" navigates ("Mitarbeiter" as "ARB");
"MITARBEITERABTEILUNG"."Mitarbeiter" as "ARB" create using "public.MitarbeiterAbteilung:mitarbeiterMethods.xsjslib::mitarbeiterCreate";
association "Mitarbeiter"
principal "ABT"("ID")
multiplicity "1"
dependent "ARB"("Abteilung")
multiplicity "*";
}
Create.xsjs:
function mitarbeiterCreate(param) {
let aAfterTableName = param.afterTableName;
var oEntry = {};
try {
var statement = param.connection.prepareStatement("SELECT * FROM\"" + aAfterTableName + "\"");
var rs = statement.executeQuery();
var statement2 = param.connection.prepareStatement('SELECT "MITARBEITERABTEILUNG"."MASEQUENCE".NEXTVAL from dummy');
var rs2 = statement2.executeQuery();
while (rs2.next()) {
oEntry.ID = rs2.getInteger(1);
}
statement2.close();
while (rs.next()) {
oEntry.Name = rs.getString(2);
oEntry.Adresse = rs.getString(3);
oEntry.bz = rs.getString(4);
oEntry.Abteilung = rs.getInteger(5);
}
statement = param.connection.prepareStatement('INSERT INTO "MITARBEITERABTEILUNG"."Mitarbeiter" VALUES (?,?,?,?,?)');
statement.setInteger(1, oEntry.ID);
statement.setString(2, oEntry.Name);
statement.setString(3, oEntry.Adresse);
statement.setString(4, oEntry.bz);
statement.setInteger(5, oEntry.Abteilung);
statement.execute();
statement.close();
} catch (e) {
statement.close();
}
}
Answered in the SAP Community here: https://answers.sap.com/questions/566957/how-to-get-the-id-of-an-inserted-record-in-hana-ba.html
The only thing you need to do, is to update the ID value in the "afterTableName" table provided by the function parameter. Something like that:
let statement = param.connection.prepareStatement('update "' + param.afterTableName + '" set ID = ' + oEntry.ID);
statement.executeUpdate();
Of course that needs to be done after you have determined your new ID. In case your column name is not "ID", please replace it with the real column name.

How can i download a file from ajax call and force the results do be downloaded

I have post the similar question yesterday and i haven't get the results. I have loaded data on my kendo grid and when i
click download, i want to download the file but it is not returning results. The folder that i am downloading from is on the server not on project solution.
I created a controller to test the download without a button click and it works but i want to download from kendo button click. No error on console
Function for getting the selected Id from the grid
function showDetails(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
DownloadIndexController(dataItem.possID);
}
Ajax call to the controller
function DownloadIndexController(possID) {
$.ajax({
url: '#Url.Action("DownloadIndex", "Poss")',
type: "GET",
data: { possID: possID },
dataType: "json",
success: function (data) {
window.location = '#Url.Action("DownloadIndex", "Poss")';
}
})
}
Controller
public ActionResult DownloadIndex(int possID)
{
string Filelocation = "myserverlocation"
FileContentResult ff = null;
try
{
OnePossModel md = new Models.OnePossModel();
JsonParamBuilder myBuilder = new JsonParamBuilder();
myBuilder.AddParam<Guid>("submittingUserID", System.Guid.Parse(User.Identity.GetUserId()));
myBuilder.AddParam<int>("possID", Convert.ToInt32(possID));
string jsonReq = Models.JsonWrapper.JsonPOST(ApiBaseUrl + ApiPOSSSubBaseUrl + "/WritePOSSFile", myBuilder.GetJSonParam());
string possFilename = Models.DeserialiseFromJson<string>.DeserialiseApiResponse(jsonReq);
possFilename = possFilename.Replace(",", ",");
string x = Filelocation + possFilename.ToString();
var type = System.Net.Mime.MediaTypeNames.Application.Octet;
byte[] fileBytes = System.IO.File.ReadAllBytes(x);
string myfileName = possFilename;
ff = File(fileBytes, type,myfileName);
Response.AppendHeader("Content-Disposition", "attachment; filename=" + myfileName);
Response.BinaryWrite(fileBytes);
return ff;
}
catch (Exception ex)
{
throw ex;
}
}
In your controller, just add this:
public FileResult DownloadIndex(int possID)
{
. . . .
return File(fileBytes, type,myfileName);
}
I don't think it can be done the way you are trying to. Take a look here for a workaround to simulate "ajax file download".
In your code you are making 2 requests, the first creates the file and stream it in the response (and cant be downloaded with ajax), and then the second request by setting the window.location - But the file is not "alive" any more since it was allocated to the first response.
If using the FileResult Action then give away the ajax call (depends on your requirements) and just use a plain link: /poss/downloadindex/123

Creating a hyperlink in active cell from uploaded file

I'm designing a shared Google Sheets for our team to keep track of each piece of content we produce. I want to implement a feature that allows people to upload a preview clip and have a hyperlink automatically created within the active cell.
My script so far serves up HTML as a user interface with a file upload and name entry. This part works fine and allows anyone to upload straight to Google Drive.
I've been having trouble getting it to automatically create a hyperlink in the active cell to the uploaded file. Been searching around, but haven't had a great deal of luck.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('File Upload')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('form.html')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Upload A File');
}
function uploadFiles(form) {
try {
var dropbox = "Clips";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription("Uploaded by " + form.myName);
return "File uploaded successfully " + file.getUrl();
} catch (error) {
return error.toString();
}
}
My suggestion is to modify the return value from uploadFiles() to be an object, then use the URL to populate a spreadsheet HYPERLINK() formula.
return "File uploaded successfully " + file.getUrl();
Becomes:
return {
result: "File uploaded successfully",
fileURL: file.getUrl(),
fileDesc: file.getDescription() // Could be other values
};
Next, a function that sets the formula. This server-side function would be called with the values to be used in the formula, which were previously returned from uploadFiles(). I'm assuming this is from your client-side JavaScript, but that's just a guess, since you didn't include that in your question.
function setHyperlink( fileURL, fileDesc ) {
var formula = '=HYPERLINK("' + fileURL + '","' + fileDesc + '")';
SpreadsheetApp.getActiveCell()
.setFormula( formula );
return true;
}
I ended up solving this issue using the GAS Properties Service - creating 2 new User Properties to contain URL and Name data.
I also found a few issues with getActiveCell - it kept placing the link in A1. Although I had used Google's suggested method for returning the active cell, I was able to use the fix suggested here:
http://bit.ly/20Gc7l6
Here's my final script
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('File Upload')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('form.html')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi()
.showModalDialog(html, 'Upload A File');
}
function uploadFiles(form) {
try {
var dropbox = "Blacksand Clips";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var blob = form.myFile;
var file = folder.createFile(blob);
file.setDescription(file.getDescription());
var userProperties = PropertiesService.getUserProperties();
var link = file.getUrl();
var name = file.getName();
userProperties.setProperty('link', link);
userProperties.setProperty('name', name);
setHyperlink();
return "File uploaded successfully ";
} catch (error) {
return error.toString();
}
}
function setHyperlink() {
var userProperties = PropertiesService.getUserProperties();
var link = userProperties.getProperty('link');
var displayName = userProperties.getProperty('name');
var value = 'hyperlink("' + link + '","' + displayName + '")'
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell().activate();
cell.setFormula( value )
return true;
}

Error Breeze OData - Metadata query failed for http://localhost:5781/odata/$metadata

I researched questions on forum but not find true result.
Error:
Metadata query failed for //localhost:5781/odata/$metadata; Unable to process returned
metadata: NamingConvention for this server property name does not roundtrip
properly:diagram_id-->Diagram_id Error: Metadata query failed for //localhost:5781/odata/$metadata; Unable to process returned metadata: NamingConvention for this server property name does not roundtrip properly:diagram_id
Code
(function () {
'use strict';
var serviceId = 'entityManagerFactory';
angular.module('myApp')
.factory(serviceId, ['breeze', emFactory]);
function emFactory(breeze) {
configureBreeze();
var serviceRoot = window.location.protocol + '//' + window.location.host + '/';
var serviceName = serviceRoot + 'odata/';
var factory = {
newManager: newManager,
serviceName: serviceName
};
return factory;
function configureBreeze() {
// use Web API OData to query and save
breeze.config.initializeAdapterInstance('dataService', 'webApiOData', true);
// convert between server-side PascalCase and client-side camelCase
breeze.NamingConvention.camelCase.setAsDefault();
}
function newManager() {
var mgr = new breeze.EntityManager(serviceName);
return mgr;
}
}})();
Code other :
(function () {
'use strict';
var serviceId = 'datacontext';
angular.module('myApp')
.factory(serviceId, ['$q', 'logger', 'entityManagerFactory', datacontext]);
function datacontext($q,logger,emFactory) {
logger = logger.forSource(serviceId);
var logError = logger.logError;
var logSuccess = logger.logSuccess;
var logWarning = logger.logWarning;
var manager = emFactory.newManager();
var service = {
getEmployees: getEmployees
};
return service;
/*Hiện thực ở đây*/
function getChangesCount(){
return manager.getChanges().length;
}
function getEmployees(forceRefresh) {
var count;
if (forceRefresh) {
if(manager.hasChanges()){
count = getChangesCount();
manager.rejectChanges();//undo tất cả các thay đổi ko được lưu
logWarning('Số nhân viên' + count + 'bị thay đổi', null, true);
}
}
// Lúc ko có forceRefesh,xem xét nhận bộ nhớ cache hơn từ xa
return breeze.EntityQuery.from('Employees')
.using(manager).execute()
.then(success).catch(failed);
function success(response) {
count = response.results.length;
logSuccess('Đã nhận ' + count + ' nhân viên', response, true);
return response.results;
}
function failed(error) {
var message = error.message || "Truy vấn để bảng nhân viên bị lỗi";
logError(message, error, true);
}
}
}})();
Code other :
(function () {
'use strict';
var controllerId = 'employees';
angular.module('myApp')
.controller(controllerId, ['datacontext', 'logger', employees]);
function employees(datacontext, logger) {
logger = logger.forSource(controllerId);
var logError = logger.logError;
var logSuccess = logger.logSuccess;
var vm = this;
vm.employees = [];
initialize();
/*Hiện thực*/
function initialize() {
getEmployees();
}
function getEmployees(forceRefresh) {
return datacontext.getEmployees(forceRefresh).then(function (data) {
return vm.employees = data;
console.log(data);
});
}
}}());
This problem very likely has to do with the camelCase naming convention and the language and/or property names that you are using. My guess is that if you remove the line that sets camelCase as the default then the error will go away. If so, then you will need to write your own custom naming convention. See http://www.breezejs.com/documentation/naming-convention
The reason that this is occurring, (I'm guessing here), is that the camelCase naming convention is very simplistic and may not work for your property names and/or language. It assumes that all server property names begin with an uppercase character and that this character can be converted to a lowercase character, and further that this process can be reversed. My guess is that one of your property names already has a first character that is lower case or that calling toLower/toUpper on some first character in a property name does not itself roundtrip. (This can occur is some non-latin character sets).
If either of these cases is occuring, its actually rather easy to create your own namingConvention to use instead of 'camelCase'. Again see the docs mentioned above.

ASP.NET MVC Open a .xls file

I have to create a .xls file from the data displayed in a table in my page. This happens when the user clicks 'export' button. I have the following code for it and it is created okay. Now, I want to open this file in the same click. How should I open it for user to see it?
string filePath = "C:/Upload/Stats_" + viewModel.SelectedTest.ToString() + ".xls";
//write the header
using (var pw = new StreamWriter(filePath, true))
{
pw.WriteLine(String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", "Month", "Total Users", "K",
"T", "G", "Detail", "GS",
"BI", "GHF","A"));
//write to the file
for (int i = 0; i < 12; i++)
{
pw.WriteLine(
String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}", viewModel.Months[i],
viewModel.M[i], viewModel.MKau[i],
viewModel.MTech[i], viewModel.MGew[i],
viewModel.MDet[i], viewModel.MGes[i],
viewModel.MBea[i], viewModel.MGesHf[i],viewModel.MAug[i]));
pw.Flush();
}
pw.Close();
}
Here I would like to open it.
I had the same 'requirement' to be able to export to xls, and instead I gave the client an export to csv, which will open in excel if you are on a machine with excel installed but is also available to other systems. I achieved it like this.
Create an extension method that supports .AsCsv, which was taken largely from Mike Hadlow's implementation
public static class EnumerableExtensions
{
public static string AsCsv<T>(this IEnumerable<T> items) where T : class
{
var csvBuilder = new StringBuilder();
var properties = typeof(T).GetProperties();
foreach (T item in items)
{
string line = string.Join(",", properties.Select(p => p.GetValue(item, null).ToCsvValue()).ToArray());
csvBuilder.AppendLine(line);
}
return csvBuilder.ToString();
}
private static string ToCsvValue<T>(this T item)
{
if (item is string)
{
return string.Format("\"{0}\"", item.ToString().Replace("\"", "\\\""));
}
double dummy;
if (double.TryParse(item.ToString(), out dummy))
{
return string.Format("{0}", item.ToString());
}
return string.Format("\"{0}\"", item.ToString());
}
}
Then you would need set your controller method to return a FileContentResult and have some logic like this within the controller method:
var outputModel = viewModel.ToList().Select(model => new
{
Months = model.Months
M = model.M[i],
MKau= model.MKau,
MTech = model.MTech,
MGew = model.MGew,
MDet = model.MDet,
MGes = model.MGes,
MBea= model.MBea,
MGesHf= model.MGesHf
});
string csv = "\"Month\",\"Total Users\",\"K\",\"T\",\"G\",\"Detail\",\"GS\",\"BI\",\"GHF\",\"A\""
+ System.Environment.NewLine
+ outputModel.AsCsv();
string fileName = "Stats_" + viewModel.SelectedTest.ToString() + ".csv"
return this.File(new System.Text.UTF8Encoding().GetBytes(csv), "text/csv", fileName);

Resources