Please can anybody point out where this code might be going wrong. I am trying to create a partial class for the masterpage.
The master pages class:
namespace MuniWeb.Models.SiteMaster{
public class BaseViewData
{
public string Title { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
}
public partial class Site : System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>
{
public Site()
{
ViewData.Model = new BaseViewData();
}
}}
The master page:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>" %>
The error:
Object reference not set to an instance of an object.
Line 33: <div id="footer">
Line 34: ApplicationID:
Line 35: <%= Model.Title %>
Line 36: </div>
Line 37: </div>
I am just using this as an example. The code I want to use needs to fire for every page to check certain parameters, this is why it is in the master page.
You shouldn't need to make a partial class. What does your controllers action code look like? The error looks like it could be from not handing the View (and therefore it's master page) a model.
Try something like this:
namespace MuniWeb.Website.ViewDataModels {
public class BaseViewData
{
public string Title { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
}
public class SubViewData : BaseViewData
{
public IList<Thing> Things { get; set; }
}
}
Then define your master page like you had:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MuniWeb.Website.ViewDataModels.BaseViewData>" %>
Now in your controller
public ActionResult Index()
{
SubViewData viewData = new SubViewData();
viewData.Title = "Page Title";
viewData.MetaKeywords = "This, that, and the other";
viewData.MetaDescription = "A really great page about this, that, and the other.";
viewData.Things = _myRepository.GetThings();
return View(viewData);
}
See how that goes...
I would ask why the MasterPage NEEDS strongly type ViewData. I understand that yes, sometimes strongly typed viewdata is needed in masterpages but generally you should be able to get way with just using the ViewData name value collection.
Shouldn't your master page be inheriting Site and not System.Web.Mvc.ViewMasterPage? No where does your master page definition actually reference the Site class.
In your code,
public partial class Site :
System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>
{
public Site()
{
ViewData.Model = new BaseViewData();
}
}}
ViewData.Model = new BaseViewData(); is not necessary. The BaseViewData should be passed in via the controller. In other words, all of your views should take look for a View that inherits the base view. The Master Page will have that same object cast as the base class BaseViewData. Your controller code appears to be correct in doing just that.
Another thing that appears to be different from my similar code is Inherits=System.Web.Mvc.ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData> should be Inherits=my.codebehind.class, then your codebehind would inherit ViewMasterPage<MuniWeb.Models.SiteMaster.BaseViewData>.
I've just not seen the code as such, perhaps it works?
Related
My app has a main dashboard which is comprised of 8 different partial views; each backed by their own view model and in my controller I'm just calling
public ActionResult mainDashboard(){
return View()
}
to return the dashboard. My question is would it be recommended to create a dashboard view model that also contains references to the view models of the partial views? What's considered a recommended best practice in this situation?
Ohkk here is a good idea as well to use html.Action instead of html.partial
This would look more like this:
public ActionResult Dashboard()
{
return View();
}
public PartialViewResult Clubs()
{
....
return PartialView(db.Clubs.ToList());//this assumes the partial view is named Clubs.cshtml, otherwise you'll need to use the overload where you pass the view name
}
public PartialViewResult Alerts()
{
....
return PartialView(db.Alerts.ToList());
}
Dashboard.cshtml
<div class="dashboard_alerts">
#Html.Action("Alerts")
<div class="dashboard_pending_clubs">
#Html.Action("Clubs")
</div>
<div class="dashboard_verified_members">
#Html.Action("Members")
</div>
OR
You would need to create a ViewModel specific for the Dashboard page precisely this would be more efficient way
public class DashboardViewModel
{
public IEnumerable<GMC.Models.Clubs> Clubs { get; set; }
public IEnumerable<GMC.Models.MemberUsers> Users { get; set; }
public IEnumerable<GMC.Models.Alerts> Alerts { get; set; }
}
Then, in the Dashboard action method, you would populate each list:
myModel.Users = db.MemberUsers.ToList();
...
You would then need to update the view to take in this new ViewModel
#model DashboardViewModel
Finally, from within the view, you would need to pass in the data to each partial:
#Html.Partial("DashboardAlerts", Model.Alerts)
#Html.Partial("DashboardClubs", Model.Clubs)
I've searched all the available tutorials I can find, and I'm still having trouble with Umbraco Surface Controllers. I've created a bare-bones Surface Controller example which sorta works, but has some issues. Here's my code so far, questions to follow:
ContactformModel1.cs:
public class ContactFormModel1
{
public string Email { get; set; }
public string Name { get; set; }
public string HoneyPot { get; set; }
public string Title { get; set; }
public string Last { get; set; }
public string First { get; set; }
public string Addr { get; set; }
public string Phone { get; set; }
public string Time { get; set; }
public string Comment { get; set; }
}
ContactSurfaceController.cs:
public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult Index()
{
return Content("this is some test content...");
}
[HttpGet]
[ActionName("ContactForm")]
public ActionResult ContactFormGet(ContactFormModel1 model)
{
return PartialView("~/Views/ContactSurface/Contact1.cshtml", model);
}
[HttpPost]
[ActionName("ContactForm")]
public ActionResult ContactFormPost(ContactFormModel1 model)
{
// Return the form, just append some exclamation points to the email address
model.Email += "!!!!";
return ContactFormGet(model);
}
public ActionResult SayOK(ContactFormModel1 model)
{
return Content("OK");
}
}
Contact.cshtml:
#model ContactFormModel1
#using (Html.BeginUmbracoForm<ContactSurfaceController>("ContactForm"))
{
#Html.EditorFor(x => Model)
<input type="submit" />
}
ContactMacroPartial.cshtml:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#Html.Action("ContactForm", "ContactSurface")
My Questions:
I'm pretty sure that return ContactFormGet(model) is wrong in the
ContactFormPost method, but everything else I've tried throws an error.
When I try return RedirectToCurrentUmbracoPage(), I get Cannot
find the Umbraco route definition in the route values, the request
must be made in the context of an Umbraco request.
When I try return CurrentUmbracoPage(), I get Can only use
UmbracoPageResult in the context of an Http POST when using a
SurfaceController form.
The routing appears to work correctly (when I put a breakpoint inside ContactFormPost, the debugger stops there). But when the form comes back, I get the exact values I submitted. I don't see the !!! appended to the email address. (Note, this bit of code is just for debugging, it's not meant to do anything useful).
How do I call the "SayOK" method in the controller? When I change the BeginUmbracoForm method to point to SayOK, I still get stuck in the ContactFormPost method.
I'm sure I'm missing something incredibly stupid, but I can't figure this out for the life of me.
I wanted to take a moment to say how I resolved this. After playing around some more, I realized that I didn't really state my problem clearly. Basically, all I'm trying to do is embed an MVC form inside a Partial View Macro, so that it could be used in the content of a page (not embedded in the template).
I could get this solution to work, but I really didn't like how much logic the author put inside the View file. So I adapted his solution this way:
Partial View Macro (cshtml) file:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#using Intrepiware.Models
#{
bool isPostback = !String.IsNullOrEmpty(Request.Form["submit-button"]);
if(isPostback)
{
#Html.Action("CreateComment", "ContactSurface", Request.Form)
}
else
{
#Html.Partial("~/Views/Partials/ContactForm.cshtml", new ContactFormModel())
}
}
Form Partial View (cshtml) file:
#using Intrepiware.Models
#using Intrepiware.Controllers
#model ContactFormModel
<p>
<span style="color: red;">#TempData["Errors"]</span>
</p>
<p>
#TempData["Success"]
</p>
<div id="cp_contact_form">
#using(Html.BeginUmbracoForm("CreateComment", "BlogPostSurface"))
{
#* Form code goes here *#
}
ContactSurfaceController.cs file:
public class ContactSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ubCreateComment(ContactFormModel model)
{
if (processComment(model) == false)
return CurrentUmbracoPage();
else
return RedirectToCurrentUmbracoPage();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateComment(ContactFormModel model)
{
if(processComment(model) == true)
{
TempData["Success"] = "Thank you for your interest. We will be in contact with you shortly.";
ModelState.Clear();
}
return PartialView("~/Views/Partials/ContactForm.cshtml");
}
private bool processComment(ContactFormModel model)
{
// Handle the model validation and processing; return true if success
}
}
The controller is designed so that the form can be embedded either in the template or a Partial View Macro. If it's embedded in a template, the form should post to ubCreateComment; if it's in a macro, post to CreateComment.
I'm almost positive there's a better/more correct way of doing this, but I ran out of time to work on the project. If someone has a better solution, please post it!
One final question/note: You'll notice that the partial view macro posts Request.Form to the ContactSurfaceController.CreateComment, and MVC magically serializes it for me. That's safe, yeah? If so, doesn't MVC rock? :)
You are using a ChildAction because you are specifying #Html.Action("ContactForm", "ContactSurface") and because of this, in your View you need to:
Use Html.BeginForm(...) and not 'Html.BeginUmbracoForm(...)'
Allow the form to post back to the same path and not to the action
If you do this, then the form will post back to itself as expected.
See the documentation here for further help.
Edit:
Just saw the final part to your question. If you intend SayOK to be your 'thank you' message, I would just call it from your HttpPost action instead of returning the initial view.
I'm new to MVC and I'm trying to add a partial view to my main layout page so I can show messages throughout my app. I'm having some trouble woring it out:
Here's my layout:
<div class="span12">
<p>
#{Html.RenderAction("Messaging", "Messaging");}
</p>
#RenderBody()
</div>
This is my messaging controller:
public ActionResult Messaging()
{
return PartialView(new ViewModels.Messaging()
{
MessageType = Utilities.MessageType.Success,
MessageHeader = "Test",
Message = "this is a test message"
});
}
Here is my partial view called _MessagingPartial.cshtml stored in the shared folder:
#model AWS.PL.ViewModels.Messaging
<span>
Model.Message
</span>
And here is my ViewModel:
public class Messaging
{
public Utilities.MessageType MessageType { get; set; }
public string MessageHeader { get; set; }
public string Message { get; set; }
}
I get the error "Partial view Messaging was not found" error. Should the partial view be called Messanging.cshtml or I'm I get the something fundamentally wrong?
Any help much appreciated.
Thanks,
Wilky.
Here is my partial view called _MessagingPartial.cshtml
Your partial view should be called Messaging.cshtml coz that's the name of the controller action that rendered it.
If you want to render a custom partial name, make sure you explicitly specify that:
public ActionResult Messaging()
{
var model = new ViewModels.Messaging
{
MessageType = Utilities.MessageType.Success,
MessageHeader = "Test",
Message = "this is a test message"
};
return PartialView("_MessagingPartial", model);
}
and if the partial is located in some non-standard location you could also specify the full path to it:
return PartialView("~/Views/FooBar/Baz/_MessagingPartial.cshtml", model);
Your guessing is right. Either partial view should be named after calling action, "Messanging.cshtml" in your case, or you should use overload to explicitly supply view name to View method
protected internal ViewResult View(
string viewName,
Object model
)
I'm developping a web site on MVC3 asp.net and I use entities framwork for data base:
I want to display the logo from database on _Layout.cshtml, and I want to display the texte from database into My home page.
this is my model
public class Theme
{
[Required(ErrorMessage = "ID is required.")]
public string ThemeID { get; set; }
public string path { get; set; }
[AllowHtml]
[Required(ErrorMessage = "Text is required.")]
public string texte { get; set; }
}
I put in the _Layout.cshtml
#Html.Partial("~/Views/Shared/_Header.cshtml")
this is my ThemeController.cs
[ChildActionOnly]
public ActionResult Header(string id)
{
var model = db.Themes.ToList();
return View("~/Views/Shared/_Header.cshtml", model);
}
this is the _Header.cshtml
#model ICollection<DSClient.Models.Theme>
#{
<img src="#Href( #Model.ElementAt(#Model-1).path )" />
}
When I type the url of Theme/index
It's OK, BUT the problem is when I load an other page, I have this exception
Object reference not set to an instance of an object.
Please Ineed your help.
Html.Partial is used to include a partial view. Therefore, when you include _Header.cshtml and the Model is not a ICollection<DSClient.Models.Theme>, you're in trouble.
Since you made a method with a Childaction attribute, I assume you may want to use Html.Action instead of Html.Partial. This would execute the child action of the controller which outputs the _Header.cshtml with the appropriate data.
Remove the string argument in the Header action (it's not used) and in _Layout.cshtml, you may call it like this:
#Html.Action("Header", "Theme")
When I display a session value in a master page (<%: Session["companyname"].ToString() %>) the following information is displayed on the page { CompanyName = TestCompany}. How do I get just the value?
Thanks for your help!
If you can show the code where the value is stored in the session, it's more likely that I could help. I would suggest, though, that you might want to reconsider using the value from the session directly in your view. It would be better, in my opinion, to have a base view model that all of your view models derive from that has the CompanyName property, and any other common properties required by your master page, on it. Your master page, then, could be strongly-typed to the base view model and you could use the values from the model. I've used this pattern with good success on a couple of projects. Couple it with a base controller where the common properties are populated for view results in OnActionExecuted(), it can be very effective in both reducing code duplication and the use of magic strings in your views.
Model:
public abstract class CommonViewModel
{
public string CompanyName { get; set; }
public string UserDisplayName { get; set; }
...
}
Controller:
public abstract class BaseController
{
public override void OnActionExecuted( ActionExecutedContext filterContext )
{
if (filterContext.Result is ViewResult)
{
var model = filterContext.ViewData.Model as CommonViewModel;
if (model != null)
{
model.CompanyName = Session["CompanyName"] as string;
model.UserDisplayName = Session["UserDisplayName"] as string;
}
}
}
}
Master Page:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<Foo.CommonViewModel>" %>
<!-- ... -->
<div>
<%: Model.CompanyName %>
</div>
<!-- ... -->
<div>
<%: Model.UserDisplayName %>
</div>