I using MVC4 and DependencyResolver with Unity. Like in Brad Wilson's blog page http://bradwilson.typepad.com/blog/2010/07/service-location-pt3-views.html, i want to use dependency injection for my views. But it seems that MVC4 view engine does not attempt to create the view page classes via the DependencyResolver. Does it, or maybe i do something wrong?
Here is my code:
public static void Register() {
var unity = new UnityContainer();
unity.RegisterType<SpaceProject.Models.SpaceShipEntities>(new RequestLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(unity));
}
public abstract class SharedView : WebViewPage
{
[Dependency]
public SpaceProject.Models.SpaceShipEntities Context { set; get; }
}
and my _Layout.cshtml:
#inherits SharedView
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head></head>
<body>
#foreach (var menu in Context.Menu) {
<li>
#menu.Title |
</li>
}
</body>
</html>
I have error that Context is null.
#inherits SharedView not work in _Layout.cshtml, i think because it is not view and used like Master Page. In views and partial views all works perfect.
Related
Hi i have just started MVC 4 in c#, i am having issue in rendering partial view.
i have created model for the partial view and controller action in which i am just
sending a single string for the testing reasons but when i try to render it.
it just show the following error.
[NullReferenceException: Object reference not set to an instance of an object.]
here is my controller class.
enter code here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using my_photos.Models;
namespace my_photos.Controllers
{
public class DefaultController : Controller
{
public ActionResult Index()
{
ViewBag.Massage = "Hello Word";
return View();
}
public ActionResult About() {
ViewBag.Message = "About Page";
return View();
}
public ActionResult _RightView() {
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
//ViewData["name"] = model;
return View(model);
}
}
here is model class for partial view
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace my_photos.Models
{
public class partial
{
public string Winner { get; set; }
}
}
here my partial view
#model my_photos.Models.partial
<div class="body">
<div class="content">
<div class="header">
<h1 class="nav-heading">Data</h1>
<p class="paragraph" > Winner :#Model.Winner.ToString() </p>
</div>
</div>
<div class="bottom">
<div class="header">
</div>
</div>
</div>
and here is my main layout in shared folder
#model my_photos.Models.partial
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>_Layout</title>
<link href="#Url.Content("~/Content/Style/Site.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/Style/Side_barnav.css")" rel="stylesheet" type="text/css" />
</head>
<body>
<header>
<h3> Photos app</h3>
<p> In this app my major concerns are with the <strong>theaming</strong>!</p>
<div class="nav">
<ul class="main-menu">
<li>#Html.ActionLink("Home","Index", "Default")</li>
<li>#Html.ActionLink("About","About", "Default")</li>
<li>#Html.ActionLink("Contact","Contact", "Default")</li>
</ul>
</div>
</header>
<section>
#RenderBody()
#Html.Partial("~/Views/Shared/_partial.cshtml")
</section>
<footer>
<div class="fotter-menu">
<ul>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("About","About","Default")</li>
<li>#Html.ActionLink("Contact","Contact","Default")</li>
</ul>
<ul>
<li>#Html.ActionLink("Resources","Resources","Default")</li>
<li>#Html.ActionLink("Testimonial","Testimonial","Default")</li>
<li>#Html.ActionLink("Team","Team","Default")</li>
</ul>
<ul>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("Home","Index","Default")</li>
<li>#Html.ActionLink("Home","Index","Default")</li>
</ul>
</div>
</footer>
</body>
</html>
when ever i try to get value form the model it give me the following error.
kindly help me through this.
[NullReferenceException: Object reference not set to an instance of an object.]
This is happening because your model is null, as you can see, in actions About and Index there is no model being passed. Also partial is a keyword in C#, it will be better to have a more signifiant name.
To solve this you have to pass a model to every view that uses that layout that is expecting this model. In your case is null and an error is thrown.
public ActionResult Index()
{
ViewBag.Massage = "Hello Word";
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
return View(model);
}
It is necesary to pass the model because on the below line of code the partial is rendered by default with the current view model.
#Html.Partial("_partial.cshtml", Model) #* Model is passed by default if there is no other parameter specified *#
I think what you really want to do is to call the _RightView action in your layout.
#Html.Action("_RightView", "Default")
Don't forget to modify the action to return a partial view and the passing of model in the other actions won't be necessary
public ActionResult _RightView() {
var model = new my_photos.Models.partial(){
Winner = "Shafee Jan"
};
//ViewData["name"] = model;
return PartialView("_partial", model);
}
hey this is not a big problem you are giving partial class reference to both layout and partial view.
so if you are access a _RightView Action it does't thrown a error because you are passing a object to view properly but when comes it partial view you are not passing object reference so just pass the model in
#Html.Partial("~/Views/Shared/_partial.cshtml",Model)
That's it
I am trying to implement angularjs routing with cshtml but i am unable to accomplish it. Can someone look into this ? what i am doing wrong.
index.cshtml:
Route 1
productmodule.js
var app = angular.module("productmodule", ["ngRoute"]);
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/route1', {
templateUrl: '/Product/Details',
controller: 'ProductController'
}).
otherwise({
redirectTo: '/'
});
}]);
Details.cshtml
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title></title>
</head>
<body>
<div ng-view=""></div>
</body>
</html>
ProductController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace webapp.Controllers
{
public class ProductController : Controller
{
//
// GET: /Product/
public ActionResult Index()
{
return View();
}
public ActionResult Details()
{
return View();
}
}
}
What i wanted to achieve is when I click the Route 1 link from ( index.cshtml) I should be able to navigate to Details.cshtml
When you click your anchor tag it's going to send a request to the server (i.e. the MVC routing) for the resource at "/". Being that you didn't specify a controller or action it will look for the default, which is Home/Index (assuming you haven't changed the default route configuration). Look for code similar to the following in your .NET project.
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" }
);
If you want Product/Index to be the default you can change "Home" to "Product". Alternatively you can change your anchor tag to specify the controller.
Route 1
Either way, MVC will deliver the Index view and at that point Angular's routing will take over, examine the "#/route1" and load the appropriate ng-view.
In a MVC3 project, I have a "_Layout.vbhtml" file with this code
<!DOCTYPE html>
<html>
<head>
</head>
<body>
...
<script src="#Url.Content("~/Scripts/jquery-1.8.2.min.js")"></script>
#RenderSection("Scripts", false)
</body>
</html>
Then, I have a Partial View "ValidationScripts.vbhtml" in the Shared folder with
#Section Scripts
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.fix.js")"></script>
<script src="#Url.Content("~/Scripts/localization/messages_de.js")"></script>
End Section
If I call the Partial View from a View like this...
#ModelType MvcExample.MyModel
#Code
ViewData("Title") = "Test"
End Code
#Html.Partial("ValidationScripts")
<h2>Just a Test</h2>
...
the Section "Scripts" is not rendered on the page, and the output HTML is
<!DOCTYPE html>
<html>
<head>
</head>
<body>
...
<script src="#Url.Content("~/Scripts/jquery-1.8.2.min.js")"></script>
</body>
</html>
How can I render the Section in the Partial View ?
I had the same issue on top of duplicate scripts, so I created a couple of Extension methods:
public static class HtmlHelperExtensions
{
private const string _jSViewDataName = "RenderJavaScript";
private const string _styleViewDataName = "RenderStyle";
public static void AddJavaScript(this HtmlHelper htmlHelper,
string scriptURL)
{
List<string> scriptList = htmlHelper.ViewContext.HttpContext
.Items[HtmlHelperExtensions._jSViewDataName] as List<string>;
if (scriptList != null)
{
if (!scriptList.Contains(scriptURL))
{
scriptList.Add(scriptURL);
}
}
else
{
scriptList = new List<string>();
scriptList.Add(scriptURL);
htmlHelper.ViewContext.HttpContext
.Items.Add(HtmlHelperExtensions._jSViewDataName, scriptList);
}
}
public static MvcHtmlString RenderJavaScripts(this HtmlHelper HtmlHelper)
{
StringBuilder result = new StringBuilder();
List<string> scriptList = HtmlHelper.ViewContext.HttpContext
.Items[HtmlHelperExtensions._jSViewDataName] as List<string>;
if (scriptList != null)
{
foreach (string script in scriptList)
{
result.AppendLine(string.Format(
"<script type=\"text/javascript\" src=\"{0}\"></script>",
script));
}
}
return MvcHtmlString.Create(result.ToString());
}
public static void AddStyle(this HtmlHelper htmlHelper, string styleURL)
{
List<string> styleList = htmlHelper.ViewContext.HttpContext
.Items[HtmlHelperExtensions._styleViewDataName] as List<string>;
if (styleList != null)
{
if (!styleList.Contains(styleURL))
{
styleList.Add(styleURL);
}
}
else
{
styleList = new List<string>();
styleList.Add(styleURL);
htmlHelper.ViewContext.HttpContext
.Items.Add(HtmlHelperExtensions._styleViewDataName, styleList);
}
}
public static MvcHtmlString RenderStyles(this HtmlHelper htmlHelper)
{
StringBuilder result = new StringBuilder();
List<string> styleList = htmlHelper.ViewContext.HttpContext
.Items[HtmlHelperExtensions._styleViewDataName] as List<string>;
if (styleList != null)
{
foreach (string script in styleList)
{
result.AppendLine(string.Format(
"<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />",
script));
}
}
return MvcHtmlString.Create(result.ToString());
}
}
On any View or Partial View or Display/Edit Template you simply add what you need:
#{
Html.AddJavaScript("http://cdn.jquerytools.org/1.2.7/full/jquery.tools.min.js");
}
In your Layouts you render it where you want it:
<!DOCTYPE html>
<html lang="en">
<head>
#Html.RenderStyles()
#Html.RenderJavascripts()
The only issue you may have is the order in which the scripts are rendered if you get to complex. If that becomes an issue, simply add the scripts to the bottom of your views/templates, and simply reverse the order in the extension method before rendering them.
You can't use sections in partial views. You can go for custom helpers as mentioned here.
I think you should be using helpers for this http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx
If you can upgrade to MVC4 you could use the new bundling and minification feature: http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification . It is specifically designed to address what you are trying to achieve (including scripts).
Alternatively you could use http://combres.codeplex.com/ with MVC3
If I understand correctly you have a structure
Layout.cshtml
View - X
PartialView Y (called inside View-X)
then you need to define the
#section Script{ .... } in the View-X and NOT PartialView Y since View-X has its View.Layout set to Layout.cshtml
all this was great info, however if you look at his original code, Section is capitalized therefore not being recognized.
it should be #section blahblah not #Section
I have a textbox in my View. I input a number into the textbox, and then i want the controller to multiply the number and put the result into the textbox.
How can I do that?
This is what i have done already.
Let's start with the View:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
</head>
<body>
<div>
<h2>Please enter a number</h2>
<% using (Html.BeginForm()) { %>
<%=Html.TextBox("number")%>
<input type="submit" value="Index" name ="Index" />
<% } %>
</div>
</body>
</html>
As you can see I have a simple textbox and button.
This is my controller:
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(int number)
{
number = number * 2;
ViewData["number"] = number;
return View(ViewData);
}
}
}
But nothing really happens. Yeah, I see the Post is being done, and the coded steps into public ActionResult Index(int number). I see that the number is taken from the textbox, it's multiplied correctly.
I've tried using ViewData as you can see. I've also used TempData.
This is another code for the textbox in the View I've tried:
<%=Html.TextBox("number", ViewData["number"])%>
But it doesn't matter. The textbox doesn't get updated with the new value. How can I do that?
Try
[HttpPost]
public ActionResult Index(int number)
{
number = number * 2;
ViewData["id"] = number;
ModelState.Clear(); // this is the key, you could also just clear ModelState for the id field
return View(ViewData);
}
You can also just use a regular html input instead of the HtmlHelper and your code would work as expected.
The default behavior of the Html helper is biting you. It looks for data in ModelState collection before using what is in ViewData. The reasoning is the normal case is a POST > Validation Fail > Return View, so showing the data the user entered is the intended behavior.
I would like my views to be able to specify a class for the <body> tag, which lies in my master page.
My first take was to do something like this:
<asp:Content ContentPlaceHolderID="BodyClassContent" runat="server">
view-item</asp:Content>
However, that would require this in the master page, which doesn't work:
<body class="<asp:ContentPlaceHolder ID="BodyClassContent" runat="server" />">
Any solutions to this?
In the layout you can do this on the body tag:
<body #RenderSection("BodyAttributes", false)>
and then in your view you can do this:
#section BodyAttributes {
id="login" class="login"
}
Edit: I also had to do this working with VB.NET and WebForms today and found a handy link for achieving the equivalent
I would suggest a different approach.
You create an hierachy of view models, starting with the MasterModel. When you instantiate a view object, you pass a body class to it.
public class MasterModel
{
string BodyCss { get; set; }
public MasterModel (string bodyCss)
{
BodyCss = bodyCss;
}
}
public class MyView1Model : MasterModel
: base ("body-view1")
{
}
Then in your master view which should be strongly typed to MasterView:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MasterModel>" %>
you just write:
<body class="<%= Model.BodyCss %>"></body>
You could also specify the body id attribute in the View which wishes to set it:
#{
ViewBag.Title = "Test";
ViewData["BodyID"] = "test";
Layout = "~/Views/Shared/_Layout.cshtml";}
This helps to decouple the view from the controller, the controller (and/or view model) does not need to know about the id attribute of the body tag.
Set the id of the body tag in the master page like so:
<body id="#ViewData["BodyID"]">
Why don't you do in your masterpage:
<body class="<%=ViewData["bodyClass"].toString()%>">
and then set ViewData["bodyClass"] in your Controller actions? That should be equivalent...