Image upload not working on Azure Storage - c#

I have just deployed my c# web application to windows azure. Image upload works fine on my local machine however now the website has been deployed the image upload doesn't work with azure storage. I just recieve an error saying Error. An error occurred while processing your request. When trying to upload an image.
Any help would be grateful.
Image Upload Controller
public ActionResult Create(UserprofileImage userprofileimage, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
if (file != null)
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var currentUser = manager.FindById(User.Identity.GetUserId());
file.SaveAs(HttpContext.Server.MapPath("~/Images/")
+ file.FileName);
userprofileimage.userImagePath = file.FileName;
userprofileimage.UserId = currentUser.Id;
userprofileimage.current = 1;
db.UserprofileImages.Add(userprofileimage);
db.SaveChanges();
var userimage = db.UserprofileImages.Where(u => u.UserId == currentUser.Id && u.Id != userprofileimage.Id).ToList();
foreach(var item in userimage)
{
item.Id = 0;
db.SaveChanges();
}
return RedirectToAction("Index", "Profile");
}
}
return View(userprofileimage);
}
** Image Upload HTML **
#using (Html.BeginForm("Create", "UserprofileImage", null, FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
<div class="control-label col-md-2">
Profile Image
</div>
<div class="col-md-10">
<input id="userImagePath" title="Upload a profile picture"
type="file" name="file" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}

As Aran suggested in the comments above, I too would recommend that you store your images in blob storage. Storing images on the hard drive should only be done for static images, which would be bundled and deployed with your solution. You cannot count on the images being present if you instance of your site is moved to another server. Storing images in SqlAzure tables or blobs will also enable you to better scale your application should you wish to increase the number of website instances you employ for you solution
Below is an example code snippet I use which gives you an idea of how to use the storage client to write to blob.
public async Task AddPhotoAsync(Photo photo)
{
var containerName = string.Format("profilepics-{0}", photo.ProfileId).ToLowerInvariant();
var blobStorage = _storageService.StorageAccount.CreateCloudBlobClient();
var cloudContainer = blobStorage.GetContainerReference("profilephotos");
if(cloudContainer.CreateIfNotExists())
{
var permissions = await cloudContainer.GetPermissionsAsync();
permissions.PublicAccess = BlobContainerPublicAccessType.Container;
cloudContainer.SetPermissions(permissions);
}
string uniqueBlobName = string.Format("profilephotos/image_{0}{1}", Guid.NewGuid().ToString(),Path.GetExtension(photo.UploadedImage.FileName));
var blob = cloudContainer.GetBlockBlobReference(uniqueBlobName);
blob.Properties.ContentType = photo.UploadedImage.ContentType;
blob.UploadFromStream(photo.UploadedImage.InputStream);
photo.Url = blob.Uri.ToString();
await AddPhotoToDB(photo);
}

Related

How to Directly Upload file to other server

So I have a project in which i want to upload video to dailymotion using api
So i want to Upload video directly to dailymotion server without uploading it to my local server
My Action
[HttpPost]
public async Task<ActionResult> Add(Video Videos)
{
var fileToUpload = #"E:\Courses\[FreeCourseLab.com] Udemy - C# Intermediate Classes, Interfaces and OOP\5. Polymorphism Third Pillar of OOP\3. Sealed Classes and Members.mp4";
return RedirectToAction("AddVideo", "Admin");
}
my View
#using (Html.BeginForm("Add", "Admin", FormMethod.Post, new { #class = "px-lg-4", role = "form" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="input-group input-group--focus mb-lg-4" style="width: 100%">
<div class="input-group-prepend"></div>
#Html.TextBoxFor(m => m.Videos.File, new {#type="file" })
</div>
<input type="submit" class="d-flex justify-content-center btn btn-block btn-primary" value="Create" />
}

Form Cannot Find Action With IFormFile

I can upload file on my local machine successfully but when i try to upload on host it can't find the action. I don't know why. Here's my code.
HTML
<form method="post" asp-action="UploadFile" asp-controller="Admin" enctype="multipart/form-data">
<div class="custom-file">
<input type="file" class="custom-file-input" id="file" name="file">
<label class="custom-file-label" for="file">Browse</label>
</div>
<button class="btn btn-brand" type="submit">Upload</button>
</form>
C#
public IActionResult UploadFile([FromForm]IFormFile file)
{
var path = Path.Combine(_environment.WebRootPath, "uploads");
if (file!= null && file.Length > 0)
{
using (var reader = new FileStream(Path.Combine(path, "gallery", file.FileName), FileMode.Create))
{
file.CopyTo(reader);
}
Gallery gallery = new Gallery
{
Path = file.FileName
};
db.Gallery.Add(gallery);
db.SaveChanges();
}
return RedirectToAction("Gallery");
}

Disabling Model Binding for Post Requests

I am trying to implement the file streaming example from https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads
As part of that, I have implemented the filter:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
var formValueProviderFactory = context.ValueProviderFactories
.OfType<FormValueProviderFactory>()
.FirstOrDefault();
if (formValueProviderFactory != null)
{
context.ValueProviderFactories.Remove(formValueProviderFactory);
}
var jqueryFormValueProviderFactory = context.ValueProviderFactories
.OfType<JQueryFormValueProviderFactory>()
.FirstOrDefault();
if (jqueryFormValueProviderFactory != null)
{
context.ValueProviderFactories
.Remove(jqueryFormValueProviderFactory);
}
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
}
I am getting an IOException
System.IO.IOException: Unexpected end of Stream, the content may have
already been read by another component.
at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.
<ReadAsync>d__36.MoveNext()
This is... vexing. I've found this question
Unexpected end of stream at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream
To which the answer is basically "Implement the DisableFormValueModelBinding Attribute". Obviously, that isn't working.
My Razor code is
<form method="post" enctype="multipart/form-data" asp-controller="FileStore" asp-action="LargeUpload">
<div class="form-group">
<!--<div class="col-md-10">
<p>Please describe your file</p>
<input type="text" name="description"/>
</div>-->
<div class="col-md-10">
<p>Upload one or more files using this form:</p>
<input type="file" name="files" multiple/>
</div>
</div>
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Large Upload" />
</div>
</div>
</form>
And my Controller is:
[HttpPost]
[DisableFormValueModelBinding]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LargeUpload()
{
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
}
//// Used to accumulate all the form url encoded key value pairs in the
//// request.
//var formAccumulator = new KeyValueAccumulator();
//string targetFilePath = null;
var boundary = MultipartRequestHelper.GetBoundary(
MediaTypeHeaderValue.Parse(Request.ContentType),
_defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
}
Does anyone know if I've missed something or if the tutorials are out of date?
I'm running VS2017 community with ASP.NET Core 1.1.2

Getting path directory from input file ASP.Net

I read up on how to get a file input to select a directory, link here how to get folder directory from html input type file or any other way
Now the issue I have is to get the list of files it picks up from the directory:
folder count
OR
Get the directory path in the backend of the ASP.Net when the user clicks on the submit button.
The code:
// POST: /Gallery/CreateImage
[HttpPost]
public ActionResult CreateImage(FormCollection collection, HttpPostedFileBase file)
{
try
{
//For each file in folder do the following
string title = collection["title"];
string description = collection["description"];
bool isSlide = collection["isSlider"] == "on" ? true : false;
bool isGallery = collection["isGallery"] == "on" ? true : false;
gallery = new Gallary(title, description, Path.GetExtension(file.FileName).Replace(".",string.Empty), isSlide, isGallery, Category.Drawing);
gallery.AddToGallery(gallery, file);
return View("GalleryManage", "Gallery");
}
catch
{
return View("GalleryManage", "Gallery");
}
}
HTML Code:
<div class="form-horizontal">
#using (Html.BeginForm("CreateFolder", "Gallery", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="box-body">
<div class="form-group">
<p>Please make sure that your folder structure is in the following format:</p>
<ol>
<li>Root Folder</li>
<li>-Art Category Folder</li>
<li>--Project Folder</li>
<li>---Images</li>
</ol>
</div>
<div class="form-group">
<label for="file">Please choose root folder</label>
<input type="file" name="folderUpload" webkitdirectory directory multiple />
</div>
<br />
<div class="box-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
}
</div>
As user3559349 points out in the comments.
I changed the CreateImage method post to ActionResult CreateImage(IEnumerable<HttpPostedFileBase> folderUpload).
I was able to get all the images uploaded.

Submit to a new page and download a file

I have code that allows users to create and edit records in a SQL database. This works fine. However, now I want it to output the SQL scripts for what is being done. I'm not sure how to do this. Here is my current code:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
<strong>ID:</strong>
<div class="col-md-10">
<p>
#Html.EditorFor(model => model.ID)
#Html.ValidationMessageFor(model => model.ID)
</div>
</div>
<br />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary">Submit <i class="fa fa-caret-right"></i></button>
</div>
</div>
</div>
}
public ActionResult Edit(int id)
{
using (var client = new XServiceClient())
{
X x = client.Find(id);
if (x == null)
{
return HttpNotFound();
}
return View(x);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(X x)
{
if (ModelState.IsValid)
{
using (var client = new XServiceClient())
{
client.Edit(x);
return Redirect("~/Home/Index");
}
}
return View(x);
}
I'm thinking in my controller I could do something like this:
using (var client = new XServiceClient())
{
var sessionID = Guid.NewGuid().ToString("N");
var filename = String.Format("Session-{0}.sql", sessionID);
var sqlString = "Update SQL String Stuff";
File(System.Text.UTF8Encoding.UTF8.GetBytes(sqlString), "text/plain", filename);
client.Edit(x);
return Redirect("~/Home/Index");
}
Most systems I have seen recommend a return on that File line. However, that won't work with the rest of the program.
How can I get my submit button to submit the data to the server and also download a file to the user?

Categories