I am currently being taught how to use MVC and my supervisor showed me how to use a repository with a read function but I'm stuck with implementing an Add function. This is my current code, thanks in advance!
Repository:
public void AddDriver(DriverModel model)
{
using (var db = new VehicleReservationEntities())
{
var newDriver = new Driver();
newDriver.DriverLastName = model.DriverLastName;
newDriver.DriverFirstName = model.DriverFirstName;
newDriver.DriverLicense = model.DriverLicense;
newDriver.LicenseExpiry = model.LicenseExpiry;
newDriver.MobileNumber = model.MobileNumber;
newDriver.BusinessUnit = model.BusinessUnit;
newDriver.DateRegistered = model.DateRegistered;
db.Driver.Add(newDriver);
db.SaveChanges();
}
}
Controller:
public ActionResult Add()
{
var repo = new VehicleRepository();
var data = repo.AddDriver();
var DVM = new DriverViewModel();
DVM.DriverLastName = data.DriverLastName;
DVM.DriverFirstName = data.DriverFirstName;
DVM.DriverLicense = data.DriverLicense;
DVM.LicenseExpiry = data.LicenseExpiry;
DVM.MobileNumber = data.MobileNumber;
DVM.BusinessUnit = data.BusinessUnit;
DVM.DateRegistered = data.DateRegistered;
db.Driver.Add();
db.SaveChanges();
}
There seems to be a few issues with what you've posted. I think you're looking for something like the following:
Controller:
[HttpPost]
public ActonResult Add(DriverViewModel DVM)
{
var repo = new VehicleRepository();
var driver = new Driver();
//tools such as automapper or tinymapper are often used so that you dont
//need to manually make these assignments
driver.DriverLastName = DVM.DriverLastName;
driver.DriverFirstName = DVM.DriverFirstName;
driver.DriverLicense = DVM.DriverLicense;
driver.LicenseExpiry = DVM.LicenseExpiry;
driver.MobileNumber = DVM.MobileNumber;
driver.BusinessUnit = DVM.BusinessUnit;
driver.DateRegistered = DVM.DateRegistered;
repo.AddDriver(driver);
//return whatever view you want to go to after the save
return View("Index");
}
Repository:
public void AddDriver(Driver newDriver)
{
using (var db = new VehicleReservationEntities())
{
db.Driver.Add(newDriver);
db.SaveChanges();
}
}
a few notes: normally, if you're using viewmodels then these viewmodels are posted to the controller instead of the raw EF entities. You were also calling db.SaveChanges in the controller as well as the repository which doesn't seem like what you want. DbSets are also normally pluralized so your call to add the driver to the db would look like db.Drivers.Add(newDriver). You've also shown 3 different classes related to Drivers: Driver, DriverModel and DriverViewModel. Sometimes this is necessary if your architecture has things separated out into multiple different layers for data access, business logic, and web however I don't see any evidence of that here. If everything exists in one project, I'd probably stick to DriverViewModel and Driver where Driver is the EF entity and DriverViewModel is what your views use and pass back to the controller
Usin ASP.NET I am trying to add a list of profiles to a object in a model and then enumerate over this list in the view.
public ActionResult Index(BlogPage currentPage)
{
var model = new BlogPageModel(currentPage);
var pages = new List<BlogPage>();
var profilePages = new List<ProfilePage>();
if (currentPage.ProfileArea != null)
{
foreach (LinkItem linkItem in currentPage.ProfileArea)
{
var page = _pageDataHelper.GetPageData(linkItem);
var profilePage = page as ProfilePage;
if (profilePage != null)
{
profilePages.Add(profilePage);
}
}
model.Profiles = profilePages;
}
return View(model);
}
Using this code in the view:
#foreach (ProfilePage profile in Model.BlogPages)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<ProfilePage>(profile))
}
However above code returns the error:
CS0030: Cannot convert type 'Models.Pages.BlogPage' to 'Models.Pages.ProfilePage'
Can someone point me the correct way to store a list inside a model and render this nested object in a view?
Thanks!
Hi Its seems that you have problem in the for each loop,but i couldn't exactly figure out the problem line, since model is not available above.
Answer to your question:
Can someone point me the correct way to store a list inside a model and render this nested object in a view?
ex:
public class somemodelname
{
public list<anytype> somepropertyname{get;set;}
}
accessing:
#foreach (var singlevalueOrObj in Model.somepropertyname)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<singlevalueOrObj >(profile))
}
In the above way you can store any list object inside your model and for rendering the page as same way as you did in the above that is using the partial view.
Hope above information was helpful.
Thanks
Karthik
You have a typo in your foreach loop:
#foreach (ProfilePage profile in Model.BlogPages)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<ProfilePage>(profile))
}
You are looping over the property BlogPages not the property Profiles that you set with a ProfilePage collection in your controller:
var pages = new List<BlogPage>();
var profilePages = new List<ProfilePage>();
if (currentPage.ProfileArea != null)
{
...shortened for length...
model.Profiles = profilePages; // Right here is what you intended to loop over
}
I'm trying to pass a List from my controller to a view.
The model as defined in my view is:
#model List<prismic.starter.Models.ResourceModel>
I am passing a List<ResourceModel> from my controller to the view:
public async Task<ActionResult> resources()
{
var docArray = await new Prismic_Connect().getAllByType("resource");
List<ResourceModel> resourceList = new List<ResourceModel>();
foreach(var doc in docArray)
{
resourceList.Add(new ResourceModel(doc));
}
return View(resourceList);
}
I can get the string value I am trying to display by writing the following:
#Model.First().getTitle();
However, when I try to loop through the list using foreach , the "title" string is not displayed.
#{
foreach (var doc in Model)
{
doc.getTitle();
}
}
What am I doing wrong here?
You missing the leading # which tells the razor engine to output the value
#foreach (var doc in Model)
{
#doc.getTitle(); // add #
}
I write that code to retrieve session values
#{
var sessionName = new Byte[20];
bool nameOK = Context.Session.TryGetValue("name", out sessionName);
if (nameOK)
{
string result = System.Text.Encoding.UTF8.GetString(sessionName);
<p> #result</p>
}
}
Is there any better way to retrieve values( using less lines etc)
A possible simplification:
At the top of your cshtml add
#using Microsoft.AspNet.Http;
This gives access to the GetString method
Context.Session.GetString("test");
I'd imagine your code simplified can then look like
#{
string sessionName = Context.Session.GetString("name");
if (sessionName != null)
{
<p>#sessionName</p>
}
}
I want to call the #Html.ActionLink method inside a c# function to return a string with a link on it.
Something like this:
string a = "Email is locked, click " + #Html.ActionLink("here to unlock.", "unlock") ;
Assuming that you want to accomplish this in your controller, there are several hoops to jump through. You must instantiate a ViewDataDictionary and a TempDataDictionary. Then you need to take the ControllerContext and create an IView. Finally, you are ready to create your HtmlHelper using all of these elements (plus your RouteCollection).
Once you have done all of this, you can use LinkExtensions.ActionLink to create your custom link. In your view, you will need to use #Html.Raw() to display your links, to prevent them from being HTML encoded. Here is the necessary code:
var vdd = new ViewDataDictionary();
var tdd = new TempDataDictionary();
var controllerContext = this.ControllerContext;
var view = new RazorView(controllerContext, "/", "/", false, null);
var html = new HtmlHelper(new ViewContext(controllerContext, view, vdd, tdd, new StringWriter()),
new ViewDataContainer(vdd), RouteTable.Routes);
var a = "Email is locked, click " + LinkExtensions.ActionLink(html, "here to unlock.", "unlock", "controller").ToString();
Having shown all of this, I will caution you that it is a much better idea to do this in your view. Add the error and other information to your ViewModel, then code your view to create the link. If this is needed across multiple views, create an HtmlHelper to do the link creation.
UPDATE
To address one.beat.consumer, my initial answer was an example of what is possible. If the developer needs to reuse this technique, the complexity can be hidden in a static helper, like so:
public static class ControllerHtml
{
// this class from internal TemplateHelpers class in System.Web.Mvc namespace
private class ViewDataContainer : IViewDataContainer
{
public ViewDataContainer(ViewDataDictionary viewData)
{
ViewData = viewData;
}
public ViewDataDictionary ViewData { get; set; }
}
private static HtmlHelper htmlHelper;
public static HtmlHelper Html(Controller controller)
{
if (htmlHelper == null)
{
var vdd = new ViewDataDictionary();
var tdd = new TempDataDictionary();
var controllerContext = controller.ControllerContext;
var view = new RazorView(controllerContext, "/", "/", false, null);
htmlHelper = new HtmlHelper(new ViewContext(controllerContext, view, vdd, tdd, new StringWriter()),
new ViewDataContainer(vdd), RouteTable.Routes);
}
return htmlHelper;
}
public static HtmlHelper Html(Controller controller, object model)
{
if (htmlHelper == null || htmlHelper.ViewData.Model == null || !htmlHelper.ViewData.Model.Equals(model))
{
var vdd = new ViewDataDictionary();
vdd.Model = model;
var tdd = new TempDataDictionary();
var controllerContext = controller.ControllerContext;
var view = new RazorView(controllerContext, "/", "/", false, null);
htmlHelper = new HtmlHelper(new ViewContext(controllerContext, view, vdd, tdd, new StringWriter()),
new ViewDataContainer(vdd), RouteTable.Routes);
}
return htmlHelper;
}
}
Then, in a controller, it is used like so:
var a = "Email is locked, click " +
ControllerHtml.Html(this).ActionLink("here to unlock.", "unlock", "controller").ToString();
or like so:
var model = new MyModel();
var text = ControllerHtml.Html(this, model).EditorForModel();
While it is easier to use Url.Action, this now extends into a powerful tool to generate any mark-up within a controller using all of the HtmlHelpers (with full Intellisense).
Possibilities of use include generating mark-up using models and Editor templates for emails, pdf generation, on-line document delivery, etc.
You could create an HtmlHelper extension method:
public static string GetUnlockText(this HtmlHelper helper)
{
string a = "Email is locked, click " + helper.ActionLink("here to unlock.", "unlock");
return a;
}
or if you mean to generate this link outside of the scope of an aspx page you'll need to create a reference to an HtmlHelper and then generate. I do this in a UrlUtility static class (I know, people hate static classes and the word Utility, but try to focus). Overload as necessary:
public static string ActionLink(string linkText, string actionName, string controllerName)
{
var httpContext = new HttpContextWrapper(System.Web.HttpContext.Current);
var requestContext = new RequestContext(httpContext, new RouteData());
var urlHelper = new UrlHelper(requestContext);
return urlHelper.ActionLink(linkText, actionName, controllerName, null);
}
Then you can write the following from wherever your heart desires:
string a = "Email is locked, click " + UrlUtility.ActionLink("here to unlock.", "unlock", "controller");
There's a couple things bad about these other answers...
Shark's answer requires you to bring the LinkExtensions namespace into C#, which is not wrong, but undesirable to me.
Hunter's idea of making a helper is a better one, but still writing a helper function for a single URL is cumbersome. You could write a helper to help you build strings that accepted parameters, or you could simply do it the old fashion way:
var link = "Email is... click, to unlock.";
#counsellorben,
i see no reason for the complexity; the user wants only to render an Action's routing into a hard string containing an anchor tag. Moreover, ActionLink() in a hard-written concatenated string buys one nothing, and forces the developer to use LinkExtensions whidh are intended for Views.
If the user is diehard about using ActionLink() or does not need (for some reason) to calculate this string in the constructor, doing so in a view is much better.
I still stand by and recommend the answers tvanfosson and I provided.
Your best bet is to construct the link manually using the UrlHelper available in the controller. Having said that, I'm suspicious that there is probably a better way to handle this in a view or partial view, shared or otherwise.
string a = "Email is locked, click <a href=\""
+ Url.Action( "unlock" )
+ "\">here to unlock.</a>";
Maybe try this:
string a = "Email is locked, click " + System.Web.Mvc.Html.LinkExtensions.ActionLink("here to unlock.", "unlock");