I'm working on my first project using ASP MVC3. My application is code first using entity framework 4.1 and SQL server CE.
The application is a document library. The main model is Document which is a path to a pdf file and a bunch of metadata.
I have a "replace" function in my controller that takes one Document record, moves the file to an archive location, and updates the database with information about the replacement.
I am trying to store a list of strings with the document that represent filepaths to older versions of the same document.
No matter what I cannot get this list, called ArchivedFilePaths, to be anything but "null".
Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace DocLibrary.Models
{
public class Document
{
public int DocumentId { get; set; }
public int CategoryId { get; set; }
public string DocumentCode { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string FileUrl { get; set; }
public int FileSize { get; set; }
public string FileSizeString { get; set; }
public int Pages { get; set; }
public string Creator { get; set; }
public int Revision { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime LastModifiedDate { get; set; }
public virtual Category Category { get; set; }
public List<String> ArchivedFilePaths { get; set; }
public SoftwareVersion SoftwareVersion { get; set; }
}
Controller:
public ActionResult Replace(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
int id = Int32.Parse(Request["DocumentId"]);
Document doc = docsDB.Documents.Find(id);
//move the current version to the ~/Archive folder
string current_path = Path.Combine(Server.MapPath("~/Files"), Path.GetFileName(doc.FileUrl));
string archiveFileName = Path.GetFileNameWithoutExtension(doc.FileUrl) + "-" + doc.Revision.ToString() + ".pdf";
string destination_path = Path.Combine(Server.MapPath("~/Archive"), archiveFileName);
System.IO.File.Move(current_path, destination_path);
if (doc.ArchivedFilePaths == null)
{
doc.ArchivedFilePaths = new List<String>();
}
doc.ArchivedFilePaths.Add(destination_path);
//there are a bunch of statements that update the title, number of pages, etc. here, all of these work fine
try
{
docsDB.Entry(doc).State = EntityState.Modified;
docsDB.Logs.Add(new Log { LogDate = DateTime.Now, LogText = "Document replaced with a new version: " + doc.Title, });
docsDB.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
//if a file was not selected;
return RedirectToAction("Index");
}
The Index view displays all of the files and their properties, including ArchivedFilePaths. After replacing a document with a new file, all of the items in the Document model update properly except ArchivedFilePaths.
If I inspect the list in VisualStudio, it is not null after the doc.ArchivedFilePaths.Add statement. So I don't believe the list is ever saved in the database and I suspect there is something wrong with my model. If I change it to a single string I can update it just fine.
Does anyone have any insight? Thanks.
Related
I’m creating a web API in MVC. The database is (thus far) simple, only three tables. I am unable to join them, though. I’ve tried three different methods for joining tables in the controller, and all return the same error, which is:
Cannot covert type (something*) to
‘Systems.Collections.Generic.IEnumerables< SalesDbApi.Sample>’ An
explicate conversion exists. Are you missing a cast?
(* The "something" portion is different depending on how the join occurs but the rest of the message remains the same, so I am assuming it is the relevant part.)
I’m guessing there is something wrong with how I have setup my Entity Relationships in Linq, because if I don’t do a join and just do a select all from Sample I get the following JSON back:
{"SampleId":10,"Barcode":"863760","CreatedAt":"2016-01-25T00:00:00","CreatedBy":10,"StatusID":3,"User":null,"Status":null}
User and Status aren’t fields in the Sample table. They are the names of the tables I am trying to link with, so I wouldn't expect them to appear.
Any idea on what I've done wrong?
Here are my three models:
Users.cs
namespace SalesDbApi
{
using System;
using System.Collections.Generic;
public partial class User
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public User()
{
this.Samples = new HashSet<Sample>();
}
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Sample> Samples { get; set; }
}
}
Statuses.cs
namespace SalesDbApi
{
using System;
using System.Collections.Generic;
public partial class Status
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Status()
{
this.Samples = new HashSet<Sample>();
}
public int StatusId { get; set; }
public string Status1 { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Sample> Samples { get; set; }
}
}
Samples.cs
namespace SalesDbApi
{
using System;
using System.Collections.Generic;
public partial class Sample
{
public int SampleId { get; set; }
public string Barcode { get; set; }
public Nullable<System.DateTime> CreatedAt { get; set; }
public int CreatedBy { get; set; }
public int StatusID { get; set; }
public virtual User User { get; set; }
public virtual Status Status { get; set; }
}
}
Here’s the code from the controller
SalesUsersController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using SalesDbApi;
namespace SalesProject.Controllers
{
public class SalesUsersController : ApiController
{
webapitestdbEntities1 db = new webapitestdbEntities1();
public IEnumerable<Sample> Get()
{
{
db.Configuration.ProxyCreationEnabled = false;
var query = from x in db.Samples
join q in db.Users
on x.CreatedBy equals q.UserId
select q.FirstName;
return query.ToList();
}
}
i think table Samples or table users not a data in database. besause linq can't accommodate table with no data.
I have a file field which is to be used to upload images and at the same time save the file path in the database. I followed this sample tutorial and adapted my code. Below is my model
using System;
using System.Web;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BOL
{
public class TeamValidation
{
[Key]
public int teamID { get; set; }
[Required(ErrorMessage = "Please Enter Your Team Name")]
[Display(Name = "Team Name")]
public string teamName { get; set; }
[DisplayName("Team Picture")]
[Required(ErrorMessage = "Please Upload Team Picture")]
[ValidateFile]
public HttpPostedFileBase teamPicture { get; set; }
//public string teamPicture { get; set; }
[Required]
[Display(Name = "Description")]
public string description { get; set; }
//[AllowHtml]
[Required(ErrorMessage = "Please Enter Team Content")]
[Display(Name = "Content")]
[MaxLength(200)]
public string content { get; set; }
}
//Customized data annotation validator for uploading file
public class ValidateFileAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
int MaxContentLength = 1024 * 1024 * 3; //3 MB
string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png" };
var file = value as HttpPostedFileBase;
if (file == null)
return false;
else if (!AllowedFileExtensions.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
{
ErrorMessage = "Please upload Your Photo of type: " + string.Join(", ", AllowedFileExtensions);
return false;
}
else if (file.ContentLength > MaxContentLength)
{
ErrorMessage = "Your Photo is too large, maximum allowed size is : " + (MaxContentLength / 1024).ToString() + "MB";
return false;
}
else
return true;
}
}
[MetadataType(typeof(TeamValidation))]
public partial class team
{
[Key]
public int teamID { get; set; }
public string teamName { get; set; }
public string teamPicture { get; set; }
public string description { get; set; }
public string content { get; set; }
}
}
and here is the controller
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BOL;
namespace TeamBuildingCompetition.Areas.Admin.Controllers
{
public class TeamController : BaseAdminController
{
// GET: Admin/Team
public ActionResult Index()
{
return View();
}
public ActionResult teamView()
{
var teamList = objBs.teamBs.GetALL();
return View(teamList);
}
[HttpPost]
public ActionResult Create(team objTeam)
{
try
{
if (ModelState.IsValid)
{
var fileName = Path.GetFileName(objTeam.teamPicture.FileName);
var path = Path.Combine(Server.MapPath("~/Content/Upload"), fileName);
objTeam.teamPicture.SaveAs(path);
TempData["Msg"] = "Created Successfully!";
objBs.teamBs.Insert(objTeam);
return RedirectToAction("Index");
}
else
{
return View("Index");
}
}
catch (Exception e1)
{
TempData["Msg"] = "Create Failed! :" + e1.Message;
return RedirectToAction("Index");
}
}
}
}
I have the errors in the snip below so I'm not able to run the file. Below is the squiggly line of error from the controller:
and also squiggly line in the model as shown below:
On hovering over the Squiggly lines, I had this error
For the TeamValidation.cs
The Error is Generate Class for HttpPostedFileBase
While the error on the TeamController for the squiggly line .FileName is
'string' does not contain a defination for 'FileName' and no extension method 'FileName' accepting a first arguement of type 'string'
Your problem is the use a partial classes and the [MetadataType] attribute on class team. Your data model has property string teamPicture and your metadata class has a conflicting property HttpPostedFileBase teamPicture. Your controller method has parameter team objTeam so objTeam.teamPicture.FileName throws an error because teamPicture is typeof string. To solve this, remove the [MetadataType] attribute from your data model, and use a view model to represent what you want to edit in the view
Data model (in namespace BOL)
public class team
{
[Key]
public int teamID { get; set; }
public string teamName { get; set; }
public string teamPicture { get; set; }
public string description { get; set; }
public string content { get; set; }
}
Then create a new folder in your project for the view model (say ViewModels). Note the teamID should not be required since the view is for creating a new team
public class TeamVM
{
[Required(ErrorMessage = "Please Enter Your Team Name")]
[Display(Name = "Team Name")]
public string TeamName { get; set; }
[DisplayName("Team Picture")]
[Required(ErrorMessage = "Please Upload Team Picture")]
[ValidateFile]
public HttpPostedFileBase TeamPicture { get; set; }
[Required]
[Display(Name = "Description")]
public string Description { get; set; }
[Required(ErrorMessage = "Please Enter Team Content")]
[Display(Name = "Content")]
[MaxLength(200)]
public string Content { get; set; }
}
Your GET method should initialize and return an instance of TeamVM
[HttpGet]
public ActionResult Create()
{
TeamVM model = new TeamVM();
return View(model);
}
and the view will be #model yourAssembly.TeamVM
Then the POST method will be
[HttpPost]
public ActionResult Create(TeamVM model)
{
....
var fileName = Path.GetFileName(model.TeamPicture.FileName);
var path = Path.Combine(Server.MapPath("~/Content/Upload"), fileName);
model.TeamPicture.SaveAs(path);
// map the view model to a new instance of the data model
team objTeam = new team
{
teamName = model.TeamName,
teamPicture = path,
description = model.Description,
content = model.Content
};
// save and redirect
objBs.teamBs.Insert(objTeam);
....
}
You use MetadataTypeAttribute and in documentation is:
You then define the metadata type as a normal class, except that you declare simple properties for each of the members to which you want to apply validation attributes.
Example from documentation:
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
... Existing members defined here, but without attributes or annotations ...
}
Then your class team should be like this:
[MetadataType(typeof(TeamValidation))]
public partial class team
{
[Key]
public int teamID { get; set; }
public string teamName { get; set; }
public HttpPostedFileBase teamPicture { get; set; }
public string description { get; set; }
public string content { get; set; }
}
I have just made a model and controller which insert new row in a custom table to my umbraco database.
I based it on petapoco tutorial http://creativewebspecialist.co.uk/2013/07/16/umbraco-petapoco-to-store-blog-comments/
Despite the script executing without errors the row is not inserted into the table.
here's what I have:
namespace MyImport.Models
{
[TableName("MyImport_Uploads")]
[PrimaryKey("ID", autoIncrement = true)]
[ExplicitColumns]
public class ImportFile
{
[Column("ID")]
[PrimaryKeyColumn(AutoIncrement=true)]
public int Id { get; set; }
[Required]
[Column("CompanyID")]
public string CompanyId { get; set; }
//public Guid CompanyId { get; set; }
[Required]
[Column("FilenameOriginal")]
public string FilenameOriginal { get; set; }
[Required]
[Column("Filename")]
public string Filename { get; set; }
[Required]
[Column("FileType")]
public string FileType { get; set; }
[Column("NumberOfItems")]
public int NumberOfItems { get; set; }
[Column("DateCreated")]
public DateTime DateCreated { get; set; }
[Column("DeleteExisting")]
public bool DeleteExisting { get; set; }
}
}
And controller:
namespace MyImport.Controllers
{
public class ImportController : SurfaceController
{
private Umbraco.Core.Persistence.UmbracoDatabase db = MyImport.Settings.UmbracoDbDSN;
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ImportExcel(ImportModel model)
{
var fileTypes = new List<string>
{
"text/xml",
"application/xml",
};
string fileType = GetFileType(model.FileUpload.ContentType);
if(model.FileUpload != null && model.FileUpload.ContentLength > 0)
{
string uploadDir = "~/imports";
string origFileName = model.FileUpload.FileName;
string extension = origFileName.Substring(origFileName.LastIndexOf('.') + 1);
string pathToCheck = Path.Combine(Server.MapPath(uploadDir), origFileName);
// Check to see if a file already exists with the
// same name as the file to upload.
if (!System.IO.File.Exists(pathToCheck))
{
string companyId = MyImport.Member.CompanyIdDummy;
string tempfileName = companyId.ToLower() + "-" + DateTime.Now.ToString("yyyyMMddHHmmss") + "." + extension;
pathToCheck = Path.Combine(Server.MapPath(uploadDir), tempfileName);
model.FileUpload.SaveAs(pathToCheck);
var importFile = new ImportFile
{
CompanyId = companyId,
Filename = tempfileName,
FilenameOriginal = origFileName,
FileType = extension,
DateCreated = DateTime.UtcNow
};
db.Insert(importFile);
}
TempData.Add("Success", true);
}
//redirect to current page to clear the form
return RedirectToCurrentUmbracoPage();
}
}
Any suggestions? Thanks
I had the database wrongly set up.
Basically I had it as umbraco.sdf in App_Data folder while I intended to use my full MSSQL database where the table was created.
I recreated the project, reinstalled umbraco and HAD to choose Customize at the bottom of the screen where I was choosing setting up cms access. This is important as I was then directed to the screen where I could set up my database connection.
Otherwise umbraco just install into SQL Server Express database which is stored in umbraco.sdf file in the project.
I hope this make sense for anyone looking for the solution to the same problem.
I'm relatively new to ASP.net mvc, and am experiencing a very strange browser error. The problem is that it's on the customer's pc (which I have yet to get access to).
There seems to be an intermittent problem posting data from his computer, at the moment he has only tried chrome (and I have requested he try different browsers). I haven't been able to replicate the issue and have tried on two computers, three browsers and three different operating systems (windows 7, windows 8 (via mac parallels) and Osx Mavericks) .
I'll post the model and relevant controller code (hopefully it's not too sloppy coding)
I've clarified the following:
- we are both using the same version of chrome
- we both use the same ISP
- He has AVG running
-the site is hosted on Azure
- there is plenty of database and file memory allocated (only 10% being used)
- very little in my code has varied from online examples and again, it all works for me
So my question is really, where else do I look to find the errors:
- is there something in the code that I should consider adding or changing
- could it be a cookie issue on his version of chrome?
- is there a firewall issue somewhere?
model
public class KitchenItem:Post
{
public virtual ICollection<Image> Images { get; set; }
//Optional Project Variables
public bool Project { get; set; }
public string ProjectName { get; set; }
public string Customer { get; set; }
public DateTime? projectStart { get; set; }
public DateTime? projectEnd { get; set; }
}
}
inherited model:
public class Post
{
public int Id
{ get; set; }
[Required]
public string Title
{ get; set; }
[Required]
[Display(Name="Short Description")]
[DataType(DataType.MultilineText )]
public string ShortDescription
{ get; set; }
[Required]
[AllowHtml]
[UIHint("tinymce_full_compressed")]
public string Description
{ get; set; }
[Display(Name = "Meta Keywords")]
[DefaultValue (" ")]
public string Meta
{ get; set; }
public string UrlSlug
{ get; set; }
public bool Published
{ get; set; }
public DateTime? PostedOn
{ get; set; }
public DateTime? Modified
{ get; set; }
public int? CategoryID { get; set; }
public Category Category
{ get; set; }
[NotMapped]
public HttpPostedFileBase uploadedFile { get; set; }
public string mainImagePath { get; set; }
public virtual ICollection<Tag> Tags
{ get; set; }
}
ViewModel:
public class CreateProjectViewModel
{
public KitchenItem KitchenItem { get; set; }
[Display(Name = "Upload Image")]
public HttpPostedFileBase[] ImagesFiles { get; set; }
public Image[] Images { get; set; }
public int CategoryID { get; set; }
public int[] imageDeletes { get; set; }
}
Create Post:
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateProjectViewModel viewModel)
{
KitchenItem model = new KitchenItem();
model = viewModel.KitchenItem;
try
{
/*
*Create ID from total Images to allow for specific folders to be created when file saved, iteration (totalImages)
*Calls for loop for each element of array to ensure that specific titles and tags are associated to correct image
* Add image to model collection to be saved to db
*/
List<Image> imgCollection = new List<Image>();
int totalKitchenItems = unitofWork.KitchenItemRepository.dbSet.Count() + 1;
//update model images
model.Images = handleEditImage(viewModel.ImagesFiles, viewModel.Images, imgCollection, model.Id);
//Log date posted
model.PostedOn = DateTime.Now;
Category cat = new Category();
model.Category = unitofWork.CategoryRepository.GetByID(viewModel.CategoryID);
//create post
unitofWork.KitchenItemRepository.Insert(model);
unitofWork.Save();
return RedirectToAction("Index");
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Class: {0}, Property: {1}, Error: {2}",
validationErrors.Entry.Entity.GetType().FullName,
validationError.PropertyName,
validationError.ErrorMessage);
}
foreach (var eve in dbEx.EntityValidationErrors)
{
Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
}
PopulateCategoriesDropDownList(0);
return RedirectToAction("Index");
}
}
Handle Image & Add Image Functions:
public ICollection<Image> handleEditImage(HttpPostedFileBase[] imageFiles, Image[] images, ICollection<Image> modelImages, int modelID)
{
/*
*Create ID from total Images to allow for specific folders to be created when file saved, iteration (totalImages)
*Calls for loop for each element of array to ensure that specific titles and tags are associated to correct image
* Add image to model collection to be saved to db
*/
List<Image> imgCollection = new List<Image>();
for (int i = 0; i < 5; i++)
{
Image uploadImage = new Image();
//check to make sure there is an image
if (imageFiles[i] != null)
{
//handle httppostedfilebase conversion to image file and add Url to image model
uploadImage = AddImage(imageFiles[i], images[i], modelID);
//Add img to be updated to model
imgCollection.Add(uploadImage);
}
}
if (modelImages != null)
{
//check for deleted images
foreach (var img in modelImages)
{
//loop through image array to determine whether image is currently assigned to model
for (int i = 0; i < 5; i++)
{
if (images[i].ImageUrl != null)
{
//replace string element modified before passed to view
images[i].ImageUrl = images[i].ImageUrl.Replace("../../", "~/");
}
if (img.ImageUrl == images[i].ImageUrl)
{
imgCollection.Add(img);
}
}
}
}
return imgCollection;
}
public Image AddImage(HttpPostedFileBase imageToSave, Image modelImage, int Id)
{
Image img = new Image();
img = modelImage;
img.ImageUrl = SaveUploadedFile(imageToSave, Id);
unitofWork.ImagesRepository.Insert(img);
return img;
}
I have set up 3 models, code first and the relationships seem to be working but one is causing me a problem.
I have Article, Language and Edition Classes
public class Article
{
public int ID { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
}
public class Language
{
public int ID { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
public class Edition
{
public int ID { get; set; }
public Article Article { get; set; }
public Language Language { get; set; }
public string Title { get; set; }
public string Details { get; set; }
}
In my bootstrap/DBinitialiser, I can create Objects and populate them fine. The DB is created and the foreign keys for Language and Article are both present on the Edition table and correctly entered.
var engLang = new Language() {Code="en", Name="English Language"};
var altLang = new Language() {Code="xx", Name="Alternative Language"};
db.Languages.Add(engLang);
db.Languages.Add(altLang);
db.SaveChanges();
var testArt = new Article() { Name = "test" };
db.Articles.Add(testArt);
db.SaveChanges();
db.Editions.Add(new Edition(){Article = testArt, Language = engLang, Title="English Content"});
db.Editions.Add(new Edition(){Article = testArt, Language = altLang, Title="Alternative Content"});
db.SaveChanges();
I can now query the Editions and return a list of them, but the Language attribute is always NULL. The Article Attribute works fine.
var query = db.Editions.Where(r => r.Article.ID == Article.ID);
foreach (Edition item in query)
{
// item.Language => NULL
// item.Article => {Object Article}
}
I'm new to .net and Entity-Framework and can't work out why I always get this error.
I can even query by r => r.Language.ID == 1 and still get a NULL attribute on the Edition object.
Make sure you are using EF codefirst in right manner. Here you have some ambiguities. You must determine what relationships actually should exist, in your POCOs. Change classes like bellow:
public class Article
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
}
public class Language
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
public class Edition
{
[Key]
public int ID { get; set; }
public virtual Article Article { get; set; }
public virtual Language Language { get; set; }
public string Title { get; set; }
public string Details { get; set; }
}
With thanks to AmirHossein Mehrvarzi for helping me write my models more clearly, I believe this error to be caused by the lazy loading of entities while iterating through the result of the query. ref: Entity Framework: There is already an open DataReader associated with this Command.
Without enabling MultipleActiveResultSets I simply added an Include statement to my linq
var query = db.Editions.Where(r => r.Article.ID == Article.ID).Include(r => r.Language);
foreach (Edition item in query)
{
// item.Language => {Object Language}
// item.Article => {Object Article}
}