Provider hosted asp.net mvc app upload file - asp.net-mvc

I am trying to create a simple post in which I am also attaching an image using Provider Hosted App on Sharepoint online, and I am not able to get SPHostUrl at Controller in HttpContext.Request, I mean SPHostUrl is missing in HttpContext.Request.
[HttpPost]
public ActionResult Contact(SimplePostModel model,HttpPostedFileBase file)
{}
View
#using (Html.BeginForm("Contact","Home",null,FormMethod.Post,new { enctype= "multipart/form-data"}))
The question is if I am sending this part new { enctype= "multipart/form-data"} in the above mentioned statement of View, I am not able to get SPHostUrl parameter in HttpContext.Request.
If I am not sending the html attributes then I am able to get SPHostUrl parameter in HttpContext.Request. and without html attributes I am also not able to upload a file.
Thanks in Advance for your help.

I have solved the issue,by changing some piece of code on in the Razor View.
#using (Html.BeginForm("Contact","Home",null,FormMethod.Post,new { enctype= "multipart/form-data"}))
Instead of null for object route values I send the spHosturl like below.
#using (Html.BeginForm("Contact","Home",new { SPHostUrl = spUrl },FormMethod.Post,new { enctype = "multipart/form-data" }))
the spUrl value comes like below
#{
var spUrl = Request.QueryString["SPHostUrl"];
}
I hope this will help for new sharepoint online developers

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.

Get full path from view in MVC .net

Im trying to upload a picture in a MVC app build on .net
I made a button :
#Html.EditorFor(model => model.Imagen,
new { htmlAttributes = new{ #class = "input", #type="file" } })
But it only gets the name of the picture. I read thats because of security reasons, so what is the simplest way of get the full path of my picture?
I can use anything (.net framework)
The uploaded file doesn't have a path until you save it somewhere. Your Action should receive an HttpPostedFileBase object from the post which you can use to do this.
A simple example:
[HttpPost]
public JsonResult Upload(HttpPostedFileBase upload)
{
var filePath = System.IO.Path.Combine(#"C:\uploads\", upload.FileName);
upload.SaveAs(filePath);
}

MVC5 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException

Ive been working on converting a MVC4 project over to MVC5. The first day I ran into an 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' but was able to resolve it by starting my conversion over. I'm not sure what the fix was which is a bummer, because its happened again.
The Error occurs in _ExternalLoginsListPartial.cshtml when I load the Login.cshtml page. The error is thrown on line 15. (string action = Model.Action;)
#using Microsoft.Owin.Security
#{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
var authenticationDescriptions = loginProviders as AuthenticationDescription[] ?? loginProviders.ToArray();
if (!authenticationDescriptions.Any())
{
<div>
<p>There are no external authentication services configured. See this article
for details on setting up this ASP.NET application to support logging in via external services.</p>
</div>
}
else
{
string action = Model.Action;
string returnUrl = Model.ReturnUrl;
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
{
#Html.AntiForgeryToken()
<div id="socialLoginList">
<p>
#foreach (AuthenticationDescription p in authenticationDescriptions)
{
<button type="submit" class="btn btn-default padded-8 margin-8" id="#p.AuthenticationType" name="provider"
value="#p.AuthenticationType" title="Log in using your #p.Caption account">
<img src="#Url.Content("~/Content/Brands/"+p.Caption+".png")" alt="Microsoft" class="img-responsive" />
<br/>
<b>#p.Caption</b>
</button>
}
</p>
</div>
}
}
}
The error thrown is
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: 'object' does not contain a definition for 'Action'
The snapshot says
Message : object' does not contain a definition for 'Action'
Source : Anonymously Hosted DynamicMethods Assembly
Now this is double weird because when I set a breakpoint Model.Action is not null. I can see the value.
This is really frustrating. The app was working 5 min ago.. I had changed the html on a non related page.. and now it wont work.
Hackish Fix
I would rather know why this error is happening. That said, I have a quick fix in case anyone else comes across this (Because this is part of part of the default solution). The solution is to not use dynamics. Create your own viewmodel and pass that.
public class ExternalLoginViewModel
{
[Display(Name = "ReturnUrl")]
public string ReturnUrl { get; set; }
[Required]
[Display(Name = "Action")]
public string Action { get; set; }
}
#Html.Partial("_ExternalLoginsListPartial", new ExternalLoginViewModel { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
Check the views in the Account folder and for each one that has an explicit model, make sure the (view)model is in the right namespace. Mouse over the m parameter (m => m.UserName ... etc) and make sure it is referencing the correct (view)model.
In my case, I moved AccountViewModels to a different folder and the app broke as above. It appears the views are sort of "caching" the model from the original namespace. I used a silly fix (commented out the #model line and un-commented it back). Got warning that m is dynamic but when built and ran it worked. Looks like a glitch in VS 2013 RTM.
This bug is verified by Microsoft, and they are working on fixing it.
So anyone from the future who reads this: try updating visual studio 2013 to at least update 2.
https://connect.microsoft.com/VisualStudio/feedback/details/813133/bug-in-mvc-5-framework-asp-net-identity-modules
Found a solution for my own (mvc5) project after some experimenting.
I had a _ExternalLoginsListShoppingCartPartial.cshtml (from my mvc4 project) with #model ICollection<AuthenticationClientData> at the top. I commented it out and rebuild the solution and suddenly it works. I'm not even using that partial view in any view so it's a pretty nasty bug imo.
So check in your project. You may have some mvc4/simplemembership stuff that is messing up your mvc5 project.
I got the same error after replacing account models to another folder. When I double checked each view under the Account folder I found out my "Manage.cshtml" referenced to old namespace. I changed it to correct namespace for my models and the error fixed.
For me I had changed the contents of the ManageUserViewModel to add a property... I then started getting the error. When I changed the Manage.cshtml from not using an explicit model to using:
#model XYZ.Models.ManageUserViewModel
and removed the using statements, it started working again. One hour wasted!
I also hit this issue with VS 2013 U3. I had just added an email field to RegisterViewModel with the [EmailAddress] attribute, and it was crashing when I tried visiting the Register page. Commenting out the [EmailAddress] attribute fixed the issue. However, it continued working after I added the attribute back in, so this is probably a broader issue that could have to do with changes to the model classes.
yeah, I replaced the "else" code with the following and its working but still trying to see why it didn't work when using Model.Action ?
//string action = Model.Action;
//string returnUrl = Model.ReturnUrl;
//using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))

asmx web service and MVC 3 - How to use Model and map web service data to it?

I have a web service and I want to display the data from web service in my MVC Razor View.
This is what I have done:
1) My Web Method:
[WebMethod]
public string HelloWorld()
{
return "Hello World... This is a Web Service consumed
through MVC Project";
}
2) Added web reference to my MVC Project
3) View :
<table><tr><td>
<input type="button" id="btnSubmit" value="Get Message"
onclick="javascript:getMessage();" />
</td></tr></table>
<div id="Result"></div>
4) Script in my view
function getMessage() {
var URL = "/Home/getMessage/";
$.get(URL, function (data) {
$("#Result").html(data);
});
}
Note : Controller name is Home and Action Method is getMessage
5) Action Method in Home
public string getMessage()
{
Service1 mvcServiceProxy = new Service1();
string message = mvcServiceProxy.HelloWorld();
return message;
}
I have followed the above steps and I am able to get the message in to my DIV as per my javascript code.
But If I have a model, and the property in my model is like: public string Message{ get; set; }
How can I get the message into this property? DO I need to modify my action method and Javascript? Should I use something like JSON ?
I am not sure of how to achive this...
I just want to use my property and display the content (message) from my web service into my Razor view using my model property instead of passing the html value into DIV and directly displaying it.
Please suggest.
Thanks in advance !!!!
First of all property is basically used to read/modify any private data in a class from another Type.
So what you are trying to achieve shouldn't be done with properties.
The way you are trying is ok, also you can get a complete list of data in one call using Json and set it on html page according to your need.
So I would recommend playing around with Json.

Getting Null value for HttpPostedFileBase with Asp.Net MVC using the latest Uploadifive

So I am trying to implement Uploadifive 1.0 with Asp.NET MVC. Using the debugger mode, I know that the upload action is successfully passed to the Controller and the Server variables are passed as well. However, the HttpPostedFileBase variable fileData is always null. I've looked everywhere on google and couldn't find an answer. I found out that the variable has to be called fileData. That doesn't help though.
Here's part of the view:
<form action="<%: Url.Action("SaveFiles", "File") %>" enctype="multipart/form-data">
<input type="file" name="file_upload" id="file_upload" />
</form>
<script type="text/javascript">
(function ($) {
$(document).ready(function () {
$('#file_upload').uploadifive({
'method': 'post',
'uploadScript': 'SaveFiles',
'formData': {'path' : 'documents'}
});
});
})(jQuery);
</script>
Here's the controller action:
[HttpPost]
public ActionResult SaveFiles(HttpPostedFileBase fileData)
{
string uploadFolder = Request.ServerVariables.Get("HTTP_X_PATH");
if(string.IsNullOrWhiteSpace(uploadFolder))
return Json(JsonMessageManager.GetFailureMessage("No upload folder was selected"));
if (fileData != null && fileData.ContentLength > 0)
{
var fileName = Path.GetFileName(fileData.FileName);
var path = Path.Combine(Server.MapPath("~/Content/" + uploadFolder), fileName);
fileData.SaveAs(path);
return Json(true);
}
return Json(false);
}
Any pointers or help would be greatly appreciated. I feel lost.
I had the exact same problem with Uploadifive so I posted on the Uploadify forums on an existing thread (probably yours). The author has since posted an update to the Uploadifive plugin which I downloaded and now this works fine for me. In fact, it works exactly like Uploadify used to including additional form data being available in "Request.Forms" and it no longer prepends the "X_" to the additional form data. I would recommend you try the new version and see how you go.
See the discussion here: http://www.uploadify.com/forum/#/discussion/8223/no-files-attached-to-request
The key is not naming your variable 'fileData,' but rather making sure that your controller and UploadiFive both think it has the same name. For example:
Javascript:
$(document).ready(function () {
$('#fileUploadDiv').uploadifive({
'uploadScript': '/File/Upload',
'fileObjName' : 'file'
});
});
C# Controller:
[HttpPost]
public PartialViewResult Upload(HttpPostedFileBase file)
{
var name = file.FileName;
var stream = file.InputStream;
// etc...
}
As long as fileObjName has the same name as the parameter in your C# controller, you should be fine. I tested it with various names, and the parameter came in null if the names didn't match, and it worked like a charm when they did match.
If the parameter still doesn't work, you should be able to access the data using this.Request.Files inside of your controller. It looks like that data comes through regardless of parameter names.

Resources