SWFUpload Authentication - asp.net-mvc

I am using SWFUpload to do file uploading in a ASP.NET MVC 1.0 website. It is working fine, but I am not able to authenticate the upload method. The HttpContext.User.Identity.Name returns an empty string. I am assuming this is because the Flash movie is making the post. I am also using the wrapper provided here: http://blog.codeville.net/2008/11/24/jquery-ajax-uploader-plugin-with-progress-bar/.
The controller action below gets fired, but as mentiond above the user object is not passed.
Any help is appreciated!
View
HTML
<form enctype="multipart/form-data" method="post" action="/Media/Upload/Photo">
<input type="file" id="userPhoto_Photo" name="userPhoto_Photo" />
</form>
Javascript
$(function() {
$("#userPhoto").makeAsyncUploader({
upload_url: '/Media/Upload',
flash_url: '<%= Url.Content("~/Content/Flash/swfUpload-2.2.0.1.swf") %>',
file_size_limit: '1 MB',
file_types: '*.jpg; *.png; *.gif',
button_action: SWFUpload.BUTTON_ACTION.SELECT_FILE,
button_width: 210,
button_height: 35,
button_image_url: '<%= Url.Content("~/Content/Images/UploadPhoto.png") %>',
button_text: '',
button_cursor: SWFUpload.CURSOR.HAND,
button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT
});
});
Controller Action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Upload()
{
if (Request.Files.Count == 1)
{
//Upload work
}
return RedirectToAction("Index", "Profile");
}

This was easily resolved with passing a post parameter, which is part of the swfUpload API. Passing user name or user id is then authenticated on the action manually using forms authentication.

You should also check out this post:
http://trycatchfail.com/blog/post/2009/05/13/Using-Flash-with-ASPNET-MVC-and-Authentication.aspx
It perfectly explains what you need to do to keep your app secure and still use Flash upload plugins like Uploadify or swfupload.

I believe this is because flash does not persist browser sessions when making requests. You would have to somehow explicitly have flash pass along some information regarding the user's session.
One way you could do this is set a cookie. Have JavaScript read the cookie and pass it off to flash. Then have flash send it along when doing uploads. This way, you are not passing in a cookie value with flash vars.
Are you using windows integrated auth?

Related

How to do File Upload Without Page Refresh or redirect in ASP.NET MVC

I am uploading a file using via a view linked to a controller however after the upload is uploaded the application is either trying to refresh or redirect and I need to prevent this. May you please point me in the right direction to avoid redirection and refresh? I have done a bit of reading and I suspect that this line action="/api/BulkUpload">might be causing the problem.
My Controller
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using Repositories.BulkUpload;
using Repositories.Interfaces.BulkUpload;
namespace SimSentinel.Controllers
{
//[Authorize]
public class BulkUploadController : ApiController
{
private readonly IBulkUploadRepository _bulkUploadRepository;
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/Files");
var provider = new FormDataStreamer(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
public class FormDataStreamer : MultipartFormDataStreamProvider
{
public FormDataStreamer(string rootPath) : base(rootPath) { }
public FormDataStreamer(string rootPath, int bufferSize) : base(rootPath, bufferSize) { }
public override string GetLocalFileName(HttpContentHeaders headers)
{
var srcFileName = headers.ContentDisposition.FileName.Replace("\"", "");
return Guid.NewGuid() + Path.GetExtension(srcFileName);
}
}
}
}
MY HTML
<form name="form1" method="post" enctype="multipart/form-data" action="/api/BulkUpload">
<div>
<label for="caption">Image Caption</label>
<input name="caption" type="text" />
</div>
<div>
<label for="image1">Image File</label>
<input name="image1" type="file" />
</div>
<div>
<input type="submit" value="ok" />
</div>
</form>
You're correct. When you submit the form, the file is sent to the controller via a HTTP POST request and the page is either, necessarily, refreshed or redirected. If you don't want to the page to refresh or redirect, then you'll have to use AJAX to post the file to the controller.
From a Mozilla Developer document on HTTP requests,
The GET method requests a representation of the specified resource.
Requests using GET should only retrieve data.
The POST method is used to submit an entity to the specified
resource, often causing a change in state or side effects on the
server.
From these notes on Web Programming from Nanyang Technological University,
[The] POST request method is used to "post" additional data up to the server
(e.g., submitting HTML form data or uploading a file). Issuing an HTTP
URL from the browser always triggers a GET request. To trigger a POST
request, you can use an HTML form with attribute method="post" or
write your own network program. For submitting HTML form data, POST
request is the same as the GET request except that the URL-encoded
query string is sent in the request body, rather than appended behind
the request-URI.
So, you can see that since you're posting a file to the server using a standard HTTP request, it is necessarily going to refresh or redirect in some way.
To avoid this, you can use jQuery to asynchronously post the file to the server without refreshing the page. There are plenty of articles on how to do this. I suggest you give it a try and post another question if you get stuck.
Upload file using jQuery and post it to Controller
ASP Snippets - Upload file using jQuery AJAX in ASP.Net MVC
C# Corner - File Upload Through JQuery AJAX In ASP.NET MVC
Thanks so much for the help it guided me in the right direction. I eventually got my answer from this [How to submit html form without redirection? . The Iframe approach is the simplest approach it is a temporary fix seeing as some articles are saying that although it is still supported by most modern browsers it has been deprecated.

Redirecting from an API

I am trying to learn/expand my knowledge of .NET MVC/REST/API's and Web-sockets/SignalR. To do this I am implementing a chat app.
I have a typical MVC intro page that gets the users name and email address in a form and that data is submitted to a RESTFul API where the new user is added to the database.
<form class="form-horizontal" role="form" action="/api/GroopsAPIUsers" method="POST">
Inside of the controller for that page(?) I'm redirecting the user to a page where they can select which room they would like to enter.
public HttpResponseMessage Post( GroopsUser userValue)
{
userValue.ID = Guid.NewGuid();
bool results = groopsRepository.AddNewUser(userValue);
// return results;
var response = Request.CreateResponse(HttpStatusCode.Redirect);
//from http://stackoverflow.com/questions/11324711/redirect-from-asp-net-web-api-post-action
string fullyQualifiedUrl = Request.RequestUri.GetLeftPart(UriPartial.Authority);
response.Headers.Location = new Uri (fullyQualifiedUrl + "/home/rooms/?userID=" + userValue.ID);
return response;
}
But this doesn't feel right. It seems like the API should only be doing CRUD operations and shouldn't have anything to do with which page the user is redirected to.
Is this the wrong approach?
If so, can someone point me in the right direction?
(I'm not sure that I've used all of these terms correctly)
...gregory
I can see why you don't think it feels right. Usually, you would design your Web API in such a way, that it is platform agnostic, so the only thing it cares about is the incoming HTTP requests, and operations based on those. When you redirect a request to another URL, you are designing around the web browser, thus constraining yourself to that one platform. Sometimes that's what you need, sometimes it isn't.
(if it indeed is what you need, then you should probably stick to just regular Asp.NET MVC, and not Web Api)
Instead of what you have now, you could make your application more flexible by returning, for example, a 200 status code from your controller, after a successful operation. That way, it is up to the client-side application to decide what to do from there. (This is where you redirect, if your client-side application is browser-based.)
So how exactly do you achieve this with your browser application? You might already have guessed it, but the answer is Javascript. Instead of making a synchronous POST request to your API, via your form, you could make the request async, and then wait for the response from the server. Then you can take an appropriate action, based on what the response contains.
A quick example:
Controller
public HttpResponseMessage Post(GroopsUser userValue)
{
userValue.ID = Guid.NewGuid();
bool results = groopsRepository.AddNewUser(userValue);
var response = Request.CreateResponse<GroopsUser>(HttpStatusCode.OK, userValue);
return response;
}
Form
<form class="form-horizontal" id="group-form" onsubmit="return addToGroup()" role="form" action="/api/GroopsAPIUsers" method="POST">
Javascript (jQuery)
<script>
function addToGroup()
{
$.ajax({
type: "POST",
url: $('#group-form').attr('action'),
data: $('#group-form').serialize(),
dataType: "json",
success: function(data) {
window.location.replace('/home/rooms/?userID=' + data.ID);
},
error: function(){
alert('error handing here');
}
});
return false;
}
</script>
If anything is unclear, or if I'm mistaken about anything, please let me know!
It depends on what you are doing with said API. You can setup an API to perform purely CRUD operations or you can make your API a lot smarter and say have it serve up actual HTML to be rendered on the client (which is sort of what MVC does) or you can take it a step further and turn it into a Hypermedia service that will define the view as well as the state of your system. The front end is then tasked with simply rendering what is provided by your API.

dropzone.js and ASP.NET MVC file posted is null?

I am trying to use dropzone.js to upload images in my ASP.NET MVC app. I am able to set-up the dropzone programatically, click on it, select the image and when I click "Open" in the file dialog, the correct Action is hit in the controller. However, the HttpPostedFileBase always comes back as null so I can't do anything with the image. ON the client-side, however, it shows the image thumbnail correctly, eventhough I can't get it on the server side.
This is the HTML:
<div style="float:left;margin-right:2px;" id="mainImage">
<img src="/images/AddImage_button.png" class="dz-message" />
</div>
This is the js code I call after the doc is ready:
var myDropzone = new Dropzone("div#mainImage", { url: "/Market/UploadImage" });
And this is the action call inside of the controller:
public ContentResult UploadImage(HttpPostedFileBase imageFile)
{
if (imageFile == null || imageFile.ContentLength == 0)
{
//.....
}
}
The action is hit but imageFile is null. Does anyone has any ideas? By the way, the "dz-message" class was added in the image placeholder inside the dropzone because before that it was not clickable. I read it somewhere that was a fix for that issue and it worked.
Any ideas why I am getting null for imageFile?
Default parameter name that Dropzone uses is file, and yours is imageFile. Change imageFile to file and it will work
There is a small tweak you may miss.
Happened to me lots of times,
The form element you use, must have it's enctype attribute set like this:
<form action="~/Home/SaveUploadedFile" method="post" enctype="multipart/form-data"/>

How to MVC Download file in AsyncControl?

I have
public class FileController : AsyncController
{
public ActionResult Download(FormCollection form)
{
FileContentResult file = new FileContentResult(Encoding.UTF8.GetBytes("10k file size"),"application/vnd.xls");
file.FileDownloadName = "test.xls";
return file;
}
}
and ofcourse, ajax form
<% var form = Ajax.BeginForm(...) %>
<input type="image" src="...gif" /> // this is my 1st attempt
<%= Ajax.ActionLink(...) %> // 2nd attempt
<% form.EndForm(); %>
i try first method(input type=image). it reach correct Action. but no file download in client side.
Then i try to use Ajax.ActionLink which i really hate. i want nice image button, not link text. Again, it reach correct Action and no file download. But if i open link in another window, there's file download !!
Q. How to make a nice file downlaod with AsyncController
Q. How to make Ajax.ActionLink lok nice
You cannot use Ajax to download files from the server. The reason for this is that even if you succeed to make the async request to the server in the success callback you will get the file contents as sent from the server and you cannot do much with this file on the client side. Remember that javascript cannot access the file system so you won't be able to save it. The way to achieve this is to have a normal HTML <form> which will point to the Download action. When this form is submitted the user will be asked to choose where he wants to save the file and the download will proceed. Also you don't need an AsyncController for this.
Here's an example:
public class FileController : Controller
{
[HttpPost]
public ActionResult Download()
{
return File(
Encoding.UTF8.GetBytes("10k file size"),
"application/vnd.xls",
"test.xls"
);
}
}
and inside your view:
<% using (Html.BeginForm("download", "file", FormMethod.Post)) { %>
<input
type="image"
src="<%: Url.Content("~/content/images/download.png") %>"
value="download"
alt="download"
/>
<% } %>
And in order to make the download button look nice, you could create a nice download.png image which will be used as form submit button.
I use this:
to disable
$('form').removeAttr("data-ajax");
to enable
$('form').attr("data-ajax", "true");
for a form with 3 submit 1 to refresh 2 to download file
All post to the same ActionResult but 2 of them have param to download as csv or as pdf
when download just disable ajax submission.
i found a way!!
just create iframe that has regular form and use jquery to trigger to.
$("iframe").contents().find("form").submit();
:D
ps credit to Firebug + Google Doc.

Redirect to an ASP.NET MVC page problem after POST request from Silverlight

In an ASP.NET MVC application I have a CartController with this AddToCart action:
public RedirectToRouteResult AddToCart(Cart cart, decimal productId,
string returnUrl)
{
Product product = productsRepository.Products
.FirstOrDefault(p => p.prodID == productId);
cart.AddItem(product);
return RedirectToAction("Index", new { returnUrl });
}
When a user submits a POST request ("Add to Cart" button) to this action from a plain ASP.NET MVC view, everything goes well: the Product is added to the Cart and the user is automatically redirected to a Cart/Index page.
If the product is submitted from a Silverlight app (which is inside an ASP.NET MVC view) it is successfully added to the Cart as well, but the there is no redirection in this case.
What is the problem? Maybe it is due to the fact that all requests from a Silverlight are asynchronous (if I'm not mistaken), and the request from a general ASP.NET MVC view is synchronous by nature? How it can affect the redirection?
In any case, how this problem could be solved?
Edited (added):
My code for sending a post request from a Silverlight app:
//first build a "paramstring" in the format "productId=126504" and then post it using this
WebClient wc = new WebClient();
wc.Headers["Content-type"] = "application/x-www-form-urlencoded";
wc.UploadStringAsync(new Uri("http://localhost:10930/Cart/AddToCart"), "POST", paramstring, "http://localhost:10930/Products");
The WebClient you are using to send the POST request will automatically follow the redirects performed on the server and return the HTML and everything ends in the success callback. If you want to redirect the user browser to this page you shouldn't use WebClient. You need javascript to submit a <form>. Silverlight allows you to execute javascript, so you could use it to dynamically generate and submit a form, or if the form already exists in the DOM set the values of the input fields and submit it.
Here's an example of how you could do this. Add the following javascript function to the same page hosting the Silverlight application:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
function addToCart(productId, returnUrl) {
var form = $(document.createElement('form'))
.attr('action', '/products/addtocart')
.attr('method', 'post')
.append(
$(document.createElement('input'))
.attr('type', 'hidden')
.attr('name', 'productId')
.val(productId)
)
.append(
$(document.createElement('input'))
.attr('type', 'hidden')
.attr('name', 'returnUrl')
.val(returnUrl)
);
$('body').append(form);
form.submit();
}
</script>
And then inside your Silverlight application whenever you decide to invoke the POST action:
HtmlPage.Window.Invoke("addToCart", "123", "http://example.com/someReturnUrl");
You may add other parameters if necessary.

Resources