I am quite new to Programming/MVC, so apologies for any incorrect terminology.
In my MVC application using Entity Framework, I am struggling to create some functionality that allows a user to upload a CSV file, parse it, and add it to my database (generated by code first).
I have a Project Model, and I want a user to be able to upload a CSV file of Deliverables for specific Projects. I will then have a View that displays Project Details, and a full list of all Deliverables as well.
Following a pretty straight forward tutorial, I have the CSV parser in my view which presents the DataTable after parsing. The View renders fine, and the this is the controller I am using:
public ActionResult Upload()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase upload)
{
if (ModelState.IsValid)
{
if (upload != null && upload.ContentLength > 0)
{
if (upload.FileName.EndsWith(".CSV"))
{
Stream stream = upload.InputStream;
DataTable csvTable = new DataTable();
using (CsvReader csvReader = new CsvReader(new StreamReader(stream), true))
{
csvTable.Load(csvReader);
}
return View(csvTable);
}
else
{
ModelState.AddModelError("File", "This file format is not supported");
return View();
}
}
else
{
ModelState.AddModelError("File", "Please Upload Your file");
}
}
return View();
}
Tutorial: http://techbrij.com/read-csv-asp-net-mvc-file-upload
I now can't for the life of me understand how I can now put this Datatable into my Deliverables table, whilst referencing the specific Project the Deliverables are for. For example, how can the code know that the deliverables in the CSV file are for Project#123 and not Project#122...
I am hoping for nudge in the right direction, and really appreciate any assistance.
Related
I am a new learner of mvc dot net. I was not Not able to clear text box values and print success message after saving data in to database using entity framework. I have created model data using entity framework.
Below is my controller and action method.
public ActionResult Registration(BookStoreMvc.Models.user obj)
{
{
if (ModelState.IsValid)
{
BookStoreMvc.Models.bookstoreEntities3 db = new BookStoreMvc.Models.bookstoreEntities3();
db.users.Add(obj);
int a = 0;
a=db.SaveChanges();
if (a>0)
{
ViewData["Message"] = "Data saved successfully";
}
this.ModelState.Clear();
}
return View(obj);
}
}
And below is the code which written in view.
#if(#Model!= null)
{
#ViewData["Message"].ToString();
}
</div>
Any one help would be deeply appreciated.
You can use it this way.
#if (ViewData["Message"] != null)
{
ViewData["Message"].ToString();
}
I need to display an image in another project from an MVC project. While accessing the image from MVC, i need to go a folder back ( or no need of the View folder name ) in the path. Following is the controller code for the view Views\Booking
public virtual ActionResult ResendEticket(BookingViewModel resendTicketModel)
{
if (ModelState.IsValid)
{
if(!string.IsNullOrEmpty(resendTicketModel.Email))
{
BookingService resendEticket = new BookingService();
string result = resendEticket.ResendEticket(Convert.ToInt32(resendTicketModel.BookingReference), resendTicketModel.Email);
if(!string.IsNullOrEmpty(result))
{
ModelState.AddModelError(string.Empty, result);
}
}
}
ModelState.AddModelError(string.Empty, "Unable to do resend ticket due to system error");
return RedirectToAction("Index", "Booking");
}
The path i am getting in the receiving side currently is
C:\ Projects\Booking\Invoices\Templates\images\logo_eticket.png
What i need is C:\ Projects\Invoices\Templates\images\logo_eticket.png
In the receiving side , i am using following code
TaxInvoiceFilePath = HttpContext.Current.Server.MapPath(mtxr.TaxInvoiceFilePath);
I may not be able to change anything on above line, as this is shared with other applications.
How can i move HttpContext.Current.Server.MapPath one step back so that all will be fine
I'll start by saying i'm a C# MVC newbie, but I've set up a site with Identity Management and extended the database with some custom tables to store additional info about my users, so I'm not a total neophyte. I've been working on a VB WPF application that I want to deploy from my new website and that is where I'm running into an issue.
I've created a new controller (User) and a couple of views (Download) & (Setup). I created a downloadmodel used by the download view.
In abstract what I am doing is displaying the download view (get) which has three checkboxes to confirm the user has read the Overview, Installation, and Terms of Service. These are boolean values in the model. I also have a string response message in the model, that displays just above the submit button. Here is the model:
public class DownloadModel
{
public bool Overview { get; set; }
public bool Installation { get; set; }
public bool TermsOfService { get; set; }
public string Response { get; set; }
public DownloadModel()
{
Overview = false;
Installation = false;
TermsOfService = false;
Response = "After checking boxes click the button to begin installation";
}
}
My User Controller handles the Get to initially display the download view, and then in the Post it checks to see if all the checkboxes were ticked, if not it updates the response message and returns the view.
If the checkboxes are all checked then it pulls the subscriber (which must exist because it was created when the user verified their e-mail via the account controller - identity management), then proceeds to update the subscriber with the original (if new) or last download date(s). At this point I want to begin downloading the clickonce setup.exe file, before returning the setup view.
[Authorize]
public class UserController : Controller
{
// GET: User/Download
public ActionResult Download()
{
return View(new DownloadModel { });
}
// Post: User/Download
[HttpPost]
public ActionResult Download(DownloadModel downloadcheck)
{
if (!ModelState.IsValid)
{
return View(downloadcheck);
}
//check to see if all the boxes were checked
if (downloadcheck.Overview == true &
downloadcheck.Installation == true &
downloadcheck.TermsOfService == true)
{
//yes - so let's proceed
//first step is to get the subscriber
Subscriber tSubscriber = new Subscriber();
tSubscriber.Email = User.Identity.Name;
bool okLoad = tSubscriber.LoadByEmail();
if (okLoad == false)
{
//we have a real problem. a user has logged in but they are not yet
//a valid subscriber?
throw new Exception("Subscriber not found");
}
// update subscriber with download in process...
if (tSubscriber.OriginalDownload == DateTime.MinValue)
{
tSubscriber.OriginalDownload = DateTime.Now;
tSubscriber.LastDownload = tSubscriber.OriginalDownload;
}
else
{
tSubscriber.LastDownload = DateTime.Now;
}
if (tSubscriber.UpdateDownloaded() == false)
{
//update of download dates failed
//another problem that shouldnt occur.
downloadcheck.Response = "A problem occured downloading your setup."
+ "Try again. If this error continues please contact support.";
return View(downloadcheck);
}
//download dates have been updated for the subscriber so let's start the download!
//THIS IS WHERE I NEED TO BEGIN THE DOWNLOAD
return View("Setup");
}
else
{
// all boxes were not checked - update message
downloadcheck.Response = "Please confirm you have reviewed the above information "
+ "by checking all of the boxes before clicking on the button.";
return View(downloadcheck);
}
}
}
The download view is pretty straight forward, and the setup view simply confirms the download was started and provides a link to the help-setup page.
I'm really a bit lost here. I thought I'd plug in a return new filepathresponse, but I can't do that and return the setup view.
My other thought was to somehow trigger the download of my /xxx/setup.exe from within the setup view as it is returned - but I'm at a loss as to how to accomplish this.
I'll be the first to admit that my mvc c# code is probably overly verbose and my approach to how I've done this may be totally wrong, but I'm just scrambling to get this done so I can deploy my WPF app to select Beta users for testing. It's been a long time living off savings and I can smell go-live from here.
One final note, I'm using setup.exe clickonce deployment of my wpf app for simplicity, as there are .net and localsqldb prerequisites, but I will not be using automated updates - not that this is really relevant.
Appreciate all input and advice.
After more digging and hacking I've found a solution that works. Firstly in my setup view (confirmation page) I added a simple script to initiate a new function in my user controller:
<script type="text/javascript">
window.location.href = "/user/sendfile/"
</script>
The controller change was simple too. For testing I just used a txt file.
// User/SendFile
public ActionResult SendFile()
{
string path = #"~/xxxx/anyfile.txt";
string content = "application/txt";
//string content = "application/x-ms-application";
return new FilePathResult(path, content)
{
FileDownloadName = "mynewtext.txt"
};
}
What is really interesting about this solution is that the FileDownloadName is what the file content is downloaded as. So in this way I can refer to the actual setup.exe file in the path, but then name the downloaded exe anything I want. Bonus :)
I am probably missing something with respect to my understanding of db.savechanges in a MVC controller. So if its something obvious, I apologize in advance.
I am using a MVC controller to import CSV records from a file. The tool I am using is CSVHelper.
I have the following working in code:
1. Calling the file in the view.
2. Executing the actionresult for the importing of records.
The csv file is accessible and is read and turned into a list. And I can tell in debug that all the records are read in to the list and their contents. Here is the code for the actionresult:
public async Task<ActionResult> ImportRecords(HttpPostedFileBase file)
{
string path = null;
List<ReportsToRecord> RTRs = new List<ReportsToRecord>();
try
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
path = AppDomain.CurrentDomain.BaseDirectory + "App_Data\\uploads\\" + fileName;
file.SaveAs(path);
var csv = new CsvReader(new StreamReader(path));
var RTRecordlist = csv.GetRecords<ReportsToRecord>();
foreach (var r in RTRecordlist)
{
ReportsToRecord RTR = new ReportsToRecord();
RTR.Id = r.Id;
RTR.REPORTING_ID = r.REPORTING_ID;
RTR.TITLE = r.TITLE;
RTR.NAME = r.NAME;
RTR.REPORTS_TO_ID = r.REPORTS_TO_ID;
RTR.EMPLOYEE_ID = r.EMPLOYEE_ID;
RTRs.Add(RTR);
}
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
catch
{
ViewData["error"] = "Upload Failed";
}
return View();
}
When I debug the RTRs.add line it does show all the records successfully read. However the await db.savechangesasync does NOT result in these records being saved.
The actual model name for the records being saved ( in Entity Framework) is ReportsToRecord with the controller name being ReportsToRecordsController.
Can anyone see in my code why the RTRs object does contain the records but these do not get saved into the ReportsToRecord model?
The only other thing I can share is that the csv file also contains the key column 'Id'. I dont know whether this is allowed or not for the savechanges operation on the imported records.Normally these keys are generating automatically in m y MVC apps.
As it stands no error comes up. The csv file's records get read in but just dont seem to be saved back to the database.
Its the typical story.Since no error comes up even in debug, the code is doing exactly what its been asked to do- BUT not what its 'Supposed to' do - which is to carry out the saving to the database.
Any insights would be appreciated. I suspect I am making some stupid error.
dumb error
i changed RTRs.Add(RTR); to
db.ReportsToRecords.Add(RTR);
and it worked
I'm using MVC 3 and using the AjaxUpload plugin to upload an image using AJAX. I don't want to save the image in the file system, instead save it to the session object and then output the stream to populate an image control on the form? Would anyone know how to do this?
No idea why would ever want to do that (store the file in session) because if you have lots of users uploading their files at the same time, storing those files in the memory of your web server, especially if those files are big, won't make this server last very long. Storing the file on the filesystem is the recommended approach.
But anyway, here's how you could do it (assuming you didn't read or cared about my previous remark):
[HttpPost]
public ActionResult Upload(MyViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var buffer = new byte[model.File.InputStream];
model.File.InputStream.Read(buffer, 0, buffer.Length);
Session["uploadedFile"] = buffer;
return View(model);
}
where the File property on the view models is a HttpPostedFileBase. Next you could have a controller action which will serve this file:
public ActionResult Image()
{
byte[] buffer = (byte[])Session["uploadedFile"];
return File(buffer, "image/png");
}
and in the view you will have an <img> tag pointing to this action:
<img src="#Url.Action("image")" alt="" />
Now of course the AjaxUpload plugin allows you to upload the file using AJAX, so you don't need to reload the entire page. So in this case your controller action could simply return a JSON object to indicate whether the upload process succeeded and then in the success callback set the src property of the <img> tag to the controller action that will serve the file.
SomeView.cshtml:
<img src="#Url.Action("/Image/Render")" />
ImageController.cs:
public ActionResult Render() {
return File((byte[])Session["Avatar"], "image/jpeg")
}
Some example code. Modify it to whatever you want to do. Not really a good idea to sling an image into a session if lots of users. Better to stick it into a db if short lived, or if long lived, a more permanent storage (filesystem maybe).
public ActionResult UploadImage()
{
foreach (string imageName in Request.Files)
{
HttpPostedFileBase file = Request.Files[imageName];
if (file.ContentLength > 0)
{
BinaryReader br = new BinaryReader(file.InputStream);
byte[] content = br.ReadBytes(file.ContentLength);
Session[imageName] = content; // better to store in a db here
}
}
return View();
}
// return the image (controller action) /mycontroller/ViewImage?imageName=whatever
public FileStreamResult ViewImage(string imageName)
{
byte[] content = (byte[])Session[imageName] ; // where ever your content is stored (ideally something other than session)
MemoryStream ms = new MemoryStream(content);
return new FileStreamResult(ms, "application/octet-stream"); // set content type based on input image, it might be png, jpg, gif etc.,
}
Hope this helps.