AngularJS Save File From ASP.NET MVC Controller - c#

I am returning a file from an ASP.NET MVC controller and I want to download it as an attachment using AngularJS.
MVC Controller:
return File(renderedBytes, mimeType);
AngularJS:
function generatePDF(reportRequest) {
var reportController = "Report";
var controllerUrl = ngAppSettings.homeBaseUri + reportController + "/GeneratePDF";
var deferred = $q.defer();
$http({
method: "POST",
url: controllerUrl,
data: reportRequest
}).success(function (data, status, headers, cfg) {
//window.open(controllerUrl, "_self", "");
deferred.resolve(data);
}).error(function (err, status) {
deferred.reject(err);
});
return deferred.promise;
};
I've tried various ways as suggested on the similar questions about this but I'm not getting it.
I've tried this too.
My breakpoints hit without any problems inside the GeneratePDF controller but nothing happens after that. How would I go about this?
EDIT:
I also tried angular file saver but I'm getting an error that the format should be in BLOB. If I can only convert the response to a blob then I think this might be it.
TIA

If your C# Controller endpoint returns a FileContentResult (which it appears that it does), then you shouldn't need to worry about promises. You can simply do the following...
function generatePDF(reportRequest) {
var reportController = "Report";
var controllerUrl = ngAppSettings.homeBaseUri + reportController + "/GeneratePDF";
window.open(controllerUrl, "_blank");
};
I am doing this in one of my apps and it is working as expected. Is there a particular reason you were using the $q service to return a promise?

Related

How to use ajax for send data to api action in another project

i acan use ajax and api action in one project and send data and update data correctly.
but when i want to send data from ajax in my project to api action in my another project,the api action dont work!
$.ajax({
type: "post",
url: urll,
error: function() {
alert("errore")
},
data: {
id: 4
},
success: function(dataa) {
alert("ok");
var x = JSON.stringify(dataa, null, '\t');
var dataaa = $.parseJSON(x);
alert(dataaa.price);
dataa.price -= 1.02;
var url2 = 'https://localhost:44337/api/apiialbums/PutAlbum';
//var url2 = 'http://localhost:51111/api/AlbumsApi/PutAlbum';
$.ajax({
type: "PUt",
//async: false,
url: url2,
//data: JSON.stringify(dataa, null, '\t'),
data: {
album: dataa
},
//contentType: "application/json; charset=utf-8", ///////
//dataType:"json",
success: function(dataaz) {
alert("updated");
alert(dataaz.price);
var x2 = JSON.stringify(dataaz, null, '\t');
alert(x2);
},
error: function() {
alert("error in update..");
}
})
}
});
and my api [httpput]action:
[HttpPut]
public async Task<ActionResult<Album>> PutAlbum([FromBody]Album album)
{
_context.Entry(album).State = EntityState.Modified;
await _context.SaveChangesAsync(); return album;
}
when i breakpoint in api action,
I understand that the program does not refer to the action
I searched the internet a lot but I could not find the reason, please help me to solve this problem as soon as possible
It's quite probable that you haven't enabled cross-origin requests. As it is stated here:
Browser security prevents a web page from making AJAX requests to another domain. This
restriction is called the same-origin policy, and prevents a malicious
site from reading sensitive data from another site. However, sometimes
you might want to let other sites call your web API.
So you have to enable first Cors. For that reason, you should go in the WebConfig class of the WebAPI that you want to be called and put the following line anywhere inside the Register method:
config.EnableCors();
Then you should go the controller, in which the PutAlbum is defined and decorate with the following attribute
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "PUT")]
You should replace "http://mywebclient.azurewebsites.net" with the URI of your Web Application, that you want to call your Web API.
UPDATE
The above apply for ASP.NET projects. For ASP.NET Core please have a look at here.
in my asp.net core project, i use following code in ConfigureServices in startup:
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("*")/*.AllowAnyOrigin()*/.AllowAnyHeader().AllowAnyMethod();
});
});
in we can use the client url instead of * :
.WithOrigins("http://localhost:51111")
and in startup in Configure use :
<pre> app.UseCors();</pre>

C# MVC Calling a method in different path using AJAX

I have a HomeController in my ASP.NET MVC application in folder "Controllers". My View is in: "View/Home/Index.cshtml" (look at my figure below).
I am using Ajax to get some json file every a few second. Problem is in Ajax URL, because I really don't know and didn't find, how to tell that property, that it has to go back a few folders and then find the HomeController.
My Solution looks like this:
Here is a method in my HomeController:
[HttpGet]
public ActionResult GetRandomFeed()
{
Item i = ss.getRandomFeed();
return Json(new { Source = i.Media.Source, Avatar = i.User.Avatar, Text = i.Text, Name = i.User.Name }, JsonRequestBehavior.AllowGet);
}
My AJAX in the View:
setInterval(function () {
$.ajax({
type: "GET",
url: '/HomeController.cs/GetRandomFeed', // Of course I have tried a lots of attempts in here
contentType: "application/json;", // Not sure about this
dataType: "json",
success: function (response) {
console.log("Success :)");
},
error: function() {
console.log("Error!");
}
});
}, 2000);
All I want to get that JSON file (or can be even an array of strings) and use it in my Success function. It is a simple Slide Show and JSON contains the URLs that I want to show in the page every X seconds (just changing source of an image that is in that JSON file).
I couldn't find anything like this. How to use that URL correctly OR found something similiar for WebForms but cannot use it in MVC.
Change your AJAX URL declaration to:
url: '/Home/GetRandomFeed'
Remove the .cs
Or you can also do, assuming this view is under your controller:
url: '#Url.Action("GetRandomFeed")'
In my experience, it doesn't seem enter the function is just because the JSON return from the controller doesn't include Status = "OK"
[HttpGet]
public ActionResult GetRandomFeed()
{
...
...
return Json(new
{
Status = "Ok", ...
}

How to convert url.HttpRouteUrl to a normal string url?

I inherited some code and I am trying to figure the right url to a webapi controller but my knowledge of mvc web api is lacking.
I have inline script that is making an ajax post like this:
$('#saveNewEducation').on('click', function () {
var educationAdd = {
'educationId': $('#newEducation').val(),
'startDate': $('#newEducationDate').val(),
'identificationId': $('#identificationId').val(),
'educationNote': $('#newEducationNote').val(),
'examinerId': $('#newExaminer').val()
};
$.post('#Url.HttpRouteUrl("DefaultApi", new { controller = "EmployeeApi", educationName = "educationCreate" })', educationAdd)
.done(function (data, textStatus, jqXhr) {
if (jqXhr.status == 200) {
$('#save-education').modal('show');
} else {
$('#fail-save-employee').modal('show');
}
})
.fail(function (jqXhr) {
var education = $("#new-education");
if (jqXhr.status == 409) {
$('#future-save-employee').modal('show');
} else {
if (jqXhr.status == 400) {
clearErrors(education);
var validationErrors = $.parseJSON(jqXhr.responseText);
$.each(validationErrors.ModelState, function (i, ival) {
remoteErrors(education, i, ival);
});
} else {
$('fail-save-employee').modal('show');
}
}
});
I don't like inline script and I have created a seperate js file where I want to make this call from.
I need help with
I need help figuring out the right url to the api controller so that i can use it in the script file.
I tried
Reading this article I tried the following:
$.post('/DefaultApi/EmployeeApi', educationAdd)
This gave me a
404 not found error.
in the inline script the url is like this:
$.post('#Url.HttpRouteUrl("DefaultApi", new { controller = "EmployeeApi", educationName = "educationCreate" })', educationAdd)
WebApiConfig.cs file:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
method I am trying to access in EmployeeApi controller:
public IHttpActionResult EducationPost(EmployeeEducation model, string educationName){}
How can I do this?
Resolving the URL
Generally in MVC applications, you would resolve this by using the Url.Action() helper to resolve the proper URL provided its Controller, Action and RouteValues:
// Supply the Action, Controller and any route values that you need
$.post('#Url.Action("EducationPost","EmployeeApi", new { educationName = "educationCreate"})', function(){
// Do something here
});
However, Web API also features the Url.Link() helper that might be useful as well and works in a similar manner except based on the route itself :
$.post('#Url.Link("DefaultApi", new { controller = "EmployeeApi", action = "EductationPost", educationName = "educationCreate" })', function(){
// Do something here
});
When using External Javascript Files
As you would imagine, these techniques won't work when using external Javascript files. What I generally recommend in these situations is to consider using a data-* attribute in HTML to store the URL and then reference that within your event handler that will trigger the AJAX call :
<button id='call-ajax' data-post-url='#Url.Action(...)' />
<script>
$(function(){
$('#call-ajax').click(function(e){
// Read the attribute and use it
$.post($(this).attr('data-post-url'), function(){
// All done
});
});
});
</script>
You could obviously accomplish this same basic idea through the use of variables or hidden elements, but the same idea basically holds true as far as actually accessing it goes.
Have a look at this answer:
How to send razor created Url to js file
This user offers 3 possible solutions.
global js variable
custom "data-" attribute
hidden input

Talking to a Web API from a Webforms application

I have an asp.net webforms application as my UI layer. This application is responsible for sending an object list down to my DAL Class Library which will then send this object list to a WebAPI for processing.
The WebAPI needs to retrieve the object list, do the processing and send an OK status code back.
Is this possible? If is there any good documentation on how this is done?
Here is what I have in my webforms app:
public static async Task<bool> MyFunction(IList<string> Ids)
{
using (var client = new HttpClient())
{
bool success = false;
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
HttpResponseMessage response = await client.GetAsync("api/products/MyProcessFunctionName");
if (response.IsSuccessStatusCode)
{
success = true;
}
return success;
}
}
I need to figure out how to send the list of string Ids to the WebApi processing function as a parameter.
I assume that you already know how to setup Web API controller in your project.
Here is a code sample for sending data from UI back to Web API controller method, which will then save that data in database,
Step 1:
In your front-end, I hope you will have a custom javascript file which handles any button click event. On that, try to send the data from UI to Web API using a POST method as shown below,
var StaffSaveRequest = {};
StaffSaveRequest.StaffDetails = {};
StaffSaveRequest.StaffDetails.Name = "Test Name";
$.ajax({
url: 'api/Staff/SaveStaff', //this is the path to web api controller method
type: 'POST',
dataType: 'json',
data: StaffSaveRequest,
success: function (response, textStatus, xhr) {
//handle success
},
error: function (xhr, textStatus, errorThrown) {
if (textStatus != 'abort') {
//handle error
}
}
});
Step 2:
Add a controller class as shown below and see the inline comments. This controller class will then interact with method in Data Access layer for saving any information.
public class StaffController : ApiController //inherits ApiController
{
[HttpPost] //add post attribute
public HttpResponseMessage SaveStaff(StaffSaveRequest staffSaveRequest)
{
try
{
var result = StaffManager.Save(staffSaveRequest);//save in database using a method in data access layer
return Request.CreateResponse(HttpStatusCode.OK, result);//result the response back
}
catch (Exception ex)
{
//log error
}
}
I hope this will give you some idea on where and how to start. Reply back, if you still have issues/questions.
You can use the Microsoft.AspNet.WebApi.Client to use your restful API.
Here is an official example from the asp.net site:
http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
If you need call your custom function MyProcessFunction first you need to define the function in the controller
public IEnumerable<string> MyProcessFunctionName()
{
return new string[] { "value1", "value2" };
}
after that, if you need to call it by name client.GetAsync("api/products/MyProcessFunctionName") you need to change the RouteConfig file to allow API calls by action name:
Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "get", id = RouteParameter.Optional }
);
It's possible to call WebApi from your webforms project. Here is a sample using WPF to call WebApi, but call should be same for webforms:
http://www.codeproject.com/Articles/611176/Calling-ASP-Net-WebAPI-using-HttpClient

How to implement file download with AJAX and MVC

I would like to provide a file download operation by using the jQuery AJAX call with some params under MVC
Example
(javascript)
function DoDownload(startDate) {
$.ajax({
url:"controller/GetFile/",
data: {startDate:startDate}
...
});
}
C# Controller Code
public void GetFile(string startDate) {
var results = doQueryWith(startDate);
// Create file based on results
....
// How do I tell the server to make this a file download??
}
I typically would just make my file download a link such as:
<a h r e f="mycontroller/getfile/1"/>Download</a>
but in the case above the date will be dynamic.
If I don't use ajax, what would be a preferred way to pass in the params to the MVC controller using javascript?
Example:
window.location = "mycontroller/GetFile/" + $("#fromDate").val();
assuming the date is 12-25-2012
Would this produce
mycontroller/GetFile/12/25/2012
would MVC treat this as three params?
What I ended up doing is calling my controller from my javascript like:
var url = "/mycontroller/GetFile?startDate=" + $("#mydate").val() + etc...
window.location = url;
mycontroller.cs
public void GetFile(DateTime startDate)
{
}
My original concern was with the date parameters. I didnt want to have to parse it.
Using the ActionLink helper, you can pass multiple params to your controller:
HtmlHelper.ActionLink(
string linkText,
string actionName,
string controllerName,
object routeValues,
object htmlAttributes
)
So in your case:
#Html.ActionLink("Download file", "GetFile", "MyController", new { startDate = "##" }, new { id="mydownloadlink" })
Using jQuery you can change the value of the startDate in the link with the content of your date picker or textbox.
$("#mydownloadlink").attr("href").replace("##", $("#yourdatetexbox").val);
Then, in your controller, just use one of the other answers here, about FileResult.
Hope this help you...
You can use the File method of controller class to return a file back to the browser.
The below sample returns a pdf file.
public ActionResult GetFile(int id)
{
var fileInfo=repositary.GetFileDedetails(id);
var byteArrayOFFile=fileInfo.FileContentAsByteArray();
return File(byteArrayOFFile,"application/pdf","yourFriendlyName.pdf");
}
Assuming repositary.GetFileDedetails method returns the details of the file from the id.
You may also return the file from a physical location(a path) or a stream. Check all the overloads of the File method and use appropriate one.
This has nothing to do with ajax. this is normal GET request over a browser.
Your controller action method should return a FileResult instead of void. And there is no need to do this via AJAX - in fact, you don't want to do this with AJAX. You'll need the browser involved so it knows to provide a download dialog for the user.
See these links:
Handling an ASP.NET MVC FileResult returned in an (jQuery) Ajax call
File download in Asp.Net MVC 2
I hope this helps.
This works for me. Make sure you return a File from your controller action with contentType as "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" and file name as e.g. "List.xlsx" which should be the same as in the AJAX success call. I have used ClosedXML NuGet package to generate the excel file.
public IActionResult GetFile(DateTime startDate)
{
var results = doQueryWith(startDate);
DataTable dt = new DataTable("Grid");
//populate dt here.
//if you result is a data table you can assign it to dt
dt = results;
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
string fileName = "List.xlsx";
using (var workbook = new XLWorkbook())
{
workbook.Worksheets.Add(dt);
using (var stream = new MemoryStream())
{
workbook.SaveAs(stream);
workbook.SaveAs(stream);
var content = stream.ToArray();
return File(content, contentType, fileName);
}
}
}
//.cshtml (JQuery AJAX call to the controller action)
$.ajax({
url:"ControllerName/GetFile/",
data: {startDate:startDate}
contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xhrFields: { responseType: 'blob' },
success: function (data) {
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'List.xlsx';
a.click();
window.URL.revokeObjectURL(url);
}
});

Categories

Resources