How to generate reports using Report Viewer in MVC 3? - asp.net-mvc-3

I have done reporting using report viewer in asp.net . Now i want to create it in MVC 3 also. As i am very new to MVC , expect guidance from you people. Thanks !!!

You need to separately populate a dataset at runtime and associate it with your report.
If you used the Report Wizard to initially create your report, it should have created a dataset definition you can use - in your case, StudentDataSource.xsd. If you open that file, you will see your query along with a TableAdapter for the query.
Here's an example based on the question Kevin referred to above ( How can I use a reportviewer control in an asp.net mvc 3 razor view? )
A StudentReport.rdlc report, with a default DataSet1 dataset and a generated StudentDataSet.xsd...
Here is the modified File() action method in PDFController:
public FileResult File() {
// Create a new dataset
StudentDataSet ds = new StudentDataSet();
// Create and fill the Student data table
// using the Student table adapter
StudentDataSetTableAdapters.StudentTableAdapter dta =
new StudentDataSetTableAdapters.StudentTableAdapter();
dta.Fill(ds.Student);
// Create a new report datasource with
// Name = the dataset name in the report,
// Value = the populated data table.
ReportDataSource rds = new ReportDataSource();
rds.Name = "DataSet1";
rds.Value = ds.Student;
ReportViewer rv = new Microsoft.Reporting.WebForms.ReportViewer();
rv.ProcessingMode = ProcessingMode.Local;
rv.LocalReport.ReportPath = Server.MapPath("~/Reports/StudentReport.rdlc");
// Add the new report datasource to the report.
rv.LocalReport.DataSources.Add(rds);
rv.LocalReport.Refresh();
byte[] streamBytes = null;
string mimeType = "";
string encoding = "";
string filenameExtension = "";
string[] streamids = null;
Warning[] warnings = null;
streamBytes = rv.LocalReport.Render("PDF", null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
return File(streamBytes, mimeType, "StudentReport.pdf");
}
Also, note that if you use this same code in the ASPXView.aspx page from the previous question, you'll need to import the namespaces for both your MVC project and the data set table adapter you are using.
ASPXView.aspx
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%# Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<%# Import Namespace="ProjectNamespace" %>
<%# Import Namespace="ProjectNamespace.StudentDataSetTableAdapters" %>
<!DOCTYPE html>
<html>
<head id="Head1" runat="server">
<title>ASPXView</title>
</head>
<body>
<div>
<script runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
StudentDataSet ds = new StudentDataSet();
StudentTableAdapter dta = new StudentTableAdapter();
dta.Fill(ds.Student);
ReportDataSource rds = new ReportDataSource();
rds.Name = "DataSet1";
rds.Value = ds.Student;
ReportViewer1.LocalReport.ReportPath = Server.MapPath("~/Reports/StudentReport.rdlc");
ReportViewer1.LocalReport.DataSources.Add(rds);
ReportViewer1.LocalReport.Refresh();
}
</script>
<form id="Form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<rsweb:reportviewer id="ReportViewer1" runat="server" height="500" width="500" AsyncRendering="false"></rsweb:reportviewer>
</form>
</div>
</body>
</html>

Related

First ajax portlet shows the seconds ones response

I am new to liferay. I want two portlet to fetch data from the two different tables of the database. The data has to be fetched automatically without refreshing the page(using ajax). The problem is the portlets I created are fetching the data and showing it properly, if one of them is deployed in a page. If both of them are deployed then they are showing the second portlets tables data i.e if only one portlet is in the portal its showing the correct data (the specific portlet's table) and automatically fetching, if both are in portal they are fetching the second deployed portlet's data(showing same data for both portlets).
Here is the jsp code of both of my portlet, I am using service builder for fetching data.
Portlet A
view.jsp
<%#page contentType="text/html"%>
<%#page pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui"%>
<%# taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<%# page import="javax.portlet.PortletContext"%>
<%# page import="com.liferay.portal.kernel.portlet.LiferayWindowState"%>
<%# page import="javax.portlet.RenderRequest"%>
<%# page import="java.util.*"%>
<%# page import="javax.portlet.*"%>
<portlet:defineObjects />
<portlet:actionURL
windowState="<%=LiferayWindowState.EXCLUSIVE.toString()%>"
var="fetchDatabase">
<portlet:param name="databaseFetch" value="fetchWorkData"></portlet:param>
</portlet:actionURL>
<%
PortletPreferences prefs = renderRequest.getPreferences();
%>
<script type="text/javascript">
var url = '<%=fetchDatabase.toString()%>';
$(document).ready(function() {
$("#fetchLink").click(function() {
$.post(url).done(function(data) {
$("#fetchData").html(data);
});
});
});
$(document).ready(function() {
//For Initial loading of database
$('#fetchData').load(url);
function timeRefresh() {
// setTimeout("location.reload(true);",timeoutPeriod);
// make a ajax call here.
$.post(url).done(function(data) {
$("#fetchData").html(data);
});
}
//Recalling the function repeatedly in given interval
setInterval(function() {
timeRefresh();
}, 6000);
});
</script>
<aui:layout id="fetchedData">
<aui:button value="Refresh" id="fetchLink"></aui:button>
<hr />
<aui:layout id="fetchData"></aui:layout>
</aui:layout>
FetchData.java
package com.cherry.ajax.database;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import com.cherry.ajax.database.service.TestLocalServiceUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.util.bridges.mvc.MVCPortlet;
/**
* Portlet implementation class FetchData
*/
public class FetchData extends MVCPortlet {
String action = "";
#Override
public void processAction(ActionRequest request, ActionResponse response)
throws IOException, PortletException {
action = request.getParameter("databaseFetch");
try {
TestLocalServiceUtil.add();
} catch (SystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void doView(RenderRequest request, RenderResponse response)
throws IOException, PortletException {
response.setContentType("text/html");
PortletRequestDispatcher dispatcher = null;
if (action.equals("fetchWorkData")) {
dispatcher = getPortletContext().getRequestDispatcher(
"/html/jsp/showData.jsp");
} else {
dispatcher = getPortletContext().getRequestDispatcher(
"/html/jsp/view.jsp");
}
action = "";
dispatcher.include(request, response);
}
}
Portlet B
view.jsp
<%#page contentType="text/html"%>
<%#page pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui"%>
<%# taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<%# page import="javax.portlet.PortletContext"%>
<%# page import="com.liferay.portal.kernel.portlet.LiferayWindowState"%>
<%# page import="javax.portlet.RenderRequest"%>
<%# page import="java.util.*"%>
<%# page import="javax.portlet.*"%>
<portlet:defineObjects />
<portlet:actionURL
windowState="<%=LiferayWindowState.EXCLUSIVE.toString()%>"
var="workloadUrl">
<portlet:param name="drAction" value="getWorkData"></portlet:param>
</portlet:actionURL>
<%
PortletPreferences prefs = renderRequest.getPreferences();
%>
<script type="text/javascript">
var url = '<%=workloadUrl.toString()%>';
$(document).ready(function() {
$("#workloadLink").click(function() {
$.post(url).done(function(data) {
$("#drData").html(data);
});
});
});
$(document).ready(function() {
//For Initial loading of database
$('#drData').load(url);
function refresh() {
// setTimeout("location.reload(true);",timeoutPeriod);
// make a ajax call here.
$.post(url).done(function(data) {
$("#drData").html(data);
});
}
//Recalling the function repeatedly in given interval
setInterval(function() {
refresh();
}, 6000);
});
</script>
<aui:layout id="DrWorkload">
<aui:button value="Refresh" id="workloadLink"></aui:button>
<hr />
<aui:layout id="drData"></aui:layout>
</aui:layout>
DrStatus.java
package com.cherry.ajax.database;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import com.cherry.ajax.database.service.WorkloadLocalServiceUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.util.bridges.mvc.MVCPortlet;
/**
* Portlet implementation class DrStatus
*/
public class DrStatus extends MVCPortlet {
String action = "";
#Override
public void processAction(ActionRequest request, ActionResponse response)
throws IOException, PortletException {
action = request.getParameter("drAction");
try {
WorkloadLocalServiceUtil.check();
} catch (SystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void doView(RenderRequest request, RenderResponse response)
throws IOException, PortletException {
response.setContentType("text/html");
PortletRequestDispatcher dispatcher = null;
if (action.equals("getWorkData")) {
dispatcher = getPortletContext().getRequestDispatcher(
"/html/drstatus/workloadData.jsp");
} else {
dispatcher = getPortletContext().getRequestDispatcher(
"/html/drstatus/view.jsp");
}
action = "";
dispatcher.include(request, response);
}
}
Please suggest me if I am doing any thing wrong ...
Thanks in advance
Samith K S
The problem is most likely that you have two DOM elements with the same ID (from both portlets). This is a common problem in portals: You never know whom you share the page with, thus you'll have to generate guaranteed-to-be-unique identifiers.
One way to do this is to use the output of <portlet:namespace/> - this is a standardized tag that generates a unique value per portlet. It's always identical within the same portlet. Then use this to generate your ID values:
<div id="<portlet:namespace />fetchData">
...
</div>
<script type="text/javascript">
var url = '<%=fetchDatabase.toString()%>';
$(document).ready(function() {
$("#fetchLink").click(function() {
$.post(url).done(function(data) {
$("#<portlet:namespace />fetchData").html(data);
});
});
});
Note: I've only used this on your example fetchData, not yet on fetchLink - that'll be your task now that you know what goes wrong :)
As you state in your comment, the same holds for variable names that end up as global variables in the DOM: Be aware that they all share the same HTML document in the end - one way to work around this is to use <portlet:namespace/> to "decorate" variable names as well, but the resulting code is ugly and hard to maintain. This is part of the reason why Liferay ended up with AlloyUI as replacement for jQuery: AUI defaults to namespacing and enables dynamic module loading. Within one namespace you didn't rely on global variables but have the variables local to that one block - including the modules that you wanted to load:
AUI().use('node', 'module2', 'module3', function (A) {
A.foo.bar()
// this variable is scoped to just this function
// no conflict with other content on the same page!
var someVariable = 'something';
doSomething();
});
As a rule, in Javascript, you should call your <aui:> components like
$('#<portlet:namespace/>aui_component_id')
If you view your html source, you'll see that all <aui> components have the 'portlet_id' as prefix in the 'id' attribute
Also, I can't understand hoe you make that work by using processAction, that is called from actionUrls. You need the 'resource' phase to fetch data without refreshing the page, so you'll need to override the MVCPortlet's serveResource function, and call it in your jsp's by calling resourceUrls
Thank you all of your resopnse.
I figure out what the problem is.
I am using same variable name for the both portlets urls (var url = '<%=workloadUrl.toString()%>'; && var url = '<%=fetchDatabase.toString()%>';).
I changed the variable name of the second portlet and now its working.
I didn't know I can't use same variable names in different portlets.

How to use knockout.js in MVC 3 Razor?

i am newbie knockout.js. Also i ama upper intermadiate in asp.net mvc 3. i really want to learn how to use knockout js in mvc 3 razor? but below code is not working also return to me empty total price. There is no error. Help please thanks...
Model:
public class GiftModel
{
public string Title { get; set; }
public double Price { get; set; }
}
View:
#using System.Web.Script.Serialization;
#model IEnumerable<knockout1.Models.GiftModel>
#{
ViewBag.Title = "Index";
}
<script src="/Scripts/knockout-2.1.0.js" type="text/javascript"></script>
<script type="text/javascript">
var initialData = #(new JavaScriptSerializer().Serialize(Model));
var viewModel = {
gifts : ko.observableArray(initialData)
};
ko.applyBindings(viewModel);
</script>
<h2>Index</h2>
<p>You have asked for <span data-bind="text: gifts().length"> </span> gift(s)</p>
Controller:
public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Index()
{
var initialState = new[] {
new GiftModel { Title = "Tall Hat", Price = 49.95 },
new GiftModel { Title = "Long Cloak", Price = 78.25 }
};
return View(initialState);
}
}
I guess you are following this tutorial.
You have a couple of errors. First replace:
var initialData = #(new JavaScriptSerializer().Serialize(Model));
with:
var initialData = #Html.Raw(Json.Encode(Model));
This ensures that your model is properly JSON encoded. In the original article Steven Sanderson is using the WebForms view engine but you seem to be using the Razor view engine. So make sure that you adapt your syntax accordingly (don't forget that the # razor function automatically html encodes the output contrary to the <%= WebForms syntax).
And the second problem with your code is that you attempted to bind your knockout model before your DOM is ready (i.e. you have placed the ko.applyBindings(viewModel); call before the actual span containing the bindings). So either wrap your call in a $(document).ready or place your scripts at the end of the document, just before closing your </body> tag (recommended).
Also I would recommend you using url helpers to reference your scripts, don't just hardcode those urls, your application will break as soon as you publish in IIS:
#model IEnumerable<GiftModel>
<h2>Index</h2>
<p>You have asked for <span data-bind="text: gifts().length"> </span> gift(s)</p>
<script src="#Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script type="text/javascript">
var initialData = #Html.Raw(Json.Encode(Model));
var viewModel = {
gifts : ko.observableArray(initialData)
};
ko.applyBindings(viewModel);
</script>
So as you can see the 2 problems you were having have strictly nothing to do with knockoutjs. So what I would recommend you if you want to learn some framework is to learn it independently. Don't mix up technologies or you will get mixed up.
So go ahead over the knockoutjs site and start the tutorials working on static HTML pages. Forget about ASP.NET MVC for the moment. Forget about Entity Framework. Just learn the framework starting from a static HTML page. This way you will better understand how it works.

Telerik MVC DatePicker Disable days of week

is there a way to have DatePicker allow user to only choose Sunday/Saturday from the popup dates since week starts from Sunday & ends on a Saturday?
I have 2 DatePickers serving as a range (from & to) and the validation is to allow the user to only select a Sunday in the from box and Saturday in the to box.
Any ideas?
Maybe you can add a jquery event handler for all the links that are week-days (the weekend days have a weekend class on the td) and prevent the default behavior, so whenever you click on them don't do anything. Also you may want to change the style of the weekday values so the user don't get annoyed for clicking and not getting the desired efect
in aspx add the below code
<%# Page Language="C#" AutoEventWireup="true" CodeFile="DefaultCS.aspx.cs" Inherits="DefaultCS" %>
<%# Register TagPrefix="radcln" Namespace="Telerik.WebControls" Assembly="RadCalendar.Net2" %>
<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<script type="text/javascript">
function OnDayRender(calendarInstance, args)
{
var jsDate = new Date(args.Date[0], args.Date[1] - 1, args.Date[2]);
if (jsDate.getDay() != 0)//(jsDate.getDay()!=6) for Saturday
{
var otherMonthCssClass = "otherMonth_" + calendarInstance.Skin;
args.Cell.className = otherMonthCssClass;
args.Cell.innerHTML = "<span>" + args.Date[2] + "</span>";
args.Cell.DayId = "";
}
}
</script>
<radcln:RadDatePicker ID="RadDatePicker1" runat="server">
<Calendar OnDayRender="Calendar_OnDayRender">
<ClientEvents OnDayRender="OnDayRender" />
</Calendar>
</radcln:RadDatePicker>
</div>
</form>
and in cs file
using System;
using System.Web.UI.WebControls;
using Telerik.WebControls;
using Telerik.WebControls.Base.Calendar.Enumerations;
public partial class DefaultCS : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
RadDatePicker1.Calendar.SpecialDays.Clear();
}
}
protected void Calendar_OnDayRender(object sender, Telerik.WebControls.Base.Calendar.Events.DayRenderEventArgs e)
{
if (e.Day.Date.DayOfWeek != DayOfWeek.Sunday) //(e.Day.Date.DayOfWeek != DayOfWeek.Saturday) for Saturday
{
string calendarSkin = RadDatePicker1.Calendar.Skin != "" ? RadDatePicker1.Calendar.Skin : "Default";
string otherMonthCssClass = String.Format("otherMonth_{0}", calendarSkin);
e.Cell.Text = "";
e.Cell.CssClass = otherMonthCssClass; //set new CssClass for the disabled calendar day cells (e.g. look like other month days here)
Label label = new Label();
label.Text = e.Day.Date.Day.ToString();
e.Cell.Controls.Add(label);
RadCalendarDay calendarDay = new RadCalendarDay();
calendarDay.Date = e.Day.Date;
calendarDay.IsSelectable = false;
calendarDay.ItemStyle.CssClass = otherMonthCssClass;
RadDatePicker1.Calendar.SpecialDays.Add(calendarDay);
}
}
}

request.getParameter() returns null

Got a homework assignment that is giving me problems.... Its modifying a JSF project with two pages and a bean to fit MVC2 by adding two more pages and a controller servlet and another bean for the two additional pages. the new main page forwards to either the second new page or the old first page. My issue is response.getParameter() always results in null.
<%#page session="false" import="java.util.Iterator"%>
<%#taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%#taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<jsp:useBean id="status" scope="request" class="JSFRegistration.Status" />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>JSP Page</title>
</head>
<body>
<% if (status!=null && !status.isSuccessful()){%>
<font color="red">Processing errors:
<ul><%Iterator errors=status.getExceptions();
while (errors.hasNext()){
Exception e = (Exception) errors.next();%>
<li><%= e.getMessage()%><%}%></ul></font><%}%>
<form action="LoginServlet" method="POST">
<% String username = request.getParameter("username");
if (username==null) username="";%>
<input type="text" name="usernameTF" value="<%=username%>" />
<% String password = request.getParameter("password");
if (password==null) password="";%>
<input type="password" name="passwordTF" value="<%=password%>" />
<input type="submit" value="Login" />
</form>
</body>
</html>
this is basically a direct copy from our book but the fields I need for the new main page. Same for the controller servlet, a direct copy except only contains the fields I need.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher view = null;
Status status = new Status();
request.setAttribute("status", status);
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username==null || username.length()==0)
status.addException(new Exception("Please enter username"));
if (password==null)
status.addException(new Exception("Please enter password"));
if (!status.isSuccessful()){
view = request.getRequestDispatcher("Login.jsp");
//view.forward(request, response);
}
else
try{
request.setAttribute("username", username);
request.setAttribute("password", password);
view = request.getRequestDispatcher("Registration.jsp");
} catch (Exception e) {
status.addException(new Exception("Error"));
view = request.getRequestDispatcher("Login.jsp");
}
view.forward(request, response);
}
and the Status class, again a direct copy from the book.
public class Status {
private ArrayList exceptions;
public Status(){
exceptions = new ArrayList();
}
public void addException(Exception exception) {
exceptions.add(exception);
}
public boolean isSuccessful(){
return (exceptions.isEmpty());
}
public Iterator getExceptions(){
return exceptions.iterator();
}
regardless of what is typed into the two boxes, stepping through a debug shows the values not getting passed to the parameters. I get the created exceptions printed above the screen for both fields if both have text, if only one has text and when both are empty.
Your request parameter names do not match the input field names. You've assigned the input fields a name of usernameTF and passwordTF. They are then available by exactly those names as request parameter, but you're attempting to get them using the names username and password. So you need either to fix the input field names, or the request parameter names so that they match each other.
By the way, why falling back from a modern MVC framework like JSF to awkward 90's style JSP with mingled business code? Is that really what the homework assignment is asking you? Also the HTML <font> element is deprecated since 1998. Where did you learn about it? Is the quality of the course really good?

Setting masterName on MVC view causes error when calling RenderAction

I have a Masterpage (site.master) that calls a View using RenderAction. At the moment the View returns "hello world".
site.master:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<html>
<head id="Head1" runat="server">
<title><asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server" /></title>
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server" />
</head>
<body>
<% Html.RenderAction("Test", "Charts"); %>
<asp:ContentPlaceHolder ID="ContentPlaceHolder3" runat="server" >
<p>site.master</p>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="ContentPlaceHolder4" runat="server" />
</body>
</html>
Test.aspx:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
hello world!
ChartsController.cs:
public ActionResult Test()
{
return View();
}
If I update the View to pass in the name of the Masterpage explicitly I get an error when I call RenderAction.
ChartsController.cs:
public ActionResult Test()
{
return View(null, "site");
}
Error:
Content controls have to be top-level controls in a content page or a nested master page that references a master page.
Stack Trace:
[HttpException (0x80004005): Content controls have to be top-level controls in a content page or a nested master page that references a master page.]
System.Web.UI.MasterPage.CreateMaster(TemplateControl owner, HttpContext context, VirtualPath masterPageFile, IDictionary contentTemplateCollection) +8857854
System.Web.UI.Page.get_Master() +54
System.Web.UI.Page.ApplyMasterPage() +15
System.Web.UI.Page.PerformPreInit() +45
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +328
How do I go about setting the master page that I want the view to use? Ultimately I will be setting the Masterpage dynamically using a custom ViewEngine (by overriding VirtualPathProviderViewEngine.FindView).
if ( String.IsNullOrEmpty(masterName) ){ masterName = "site"; }
When I set the masterName property in my ViewEngine and then call RenderAction from site.master I get the same error as when I set the masterName property in the Action.
I am using:
Visual Studio 2010
MVC 3
IIS Express
edited: added full site.master markup
Subclass ViewPage<T> and override the OnPreInit() event. In your override,
protected override void OnPreInit(EventArgs e)
{
this.MasterLocation = GetMasterLocation();
base.OnPreInit(e);
}
The GetMasterLocation() method should get the filename of the view (beginning with a "~/").
The error comes from the CreateMaster method in MasterPage, the code that throws it is:
if (masterPageFile == null)
{
if ((contentTemplateCollection != null) && (contentTemplateCollection.Count > 0))
{
throw new HttpException(SR.GetString("Content_only_allowed_in_content_page"));
}
return null;
}
So, the MasterPage doesn't exist and content template collection has templates, so the page throws an exception. Following the above instructions will programmatically set the masterpage's location (which gets processed into the virtual path which is the variable masterPageFile)
I have come up with a solution and at least a partial answer/understanding to the cause of my issue.
If I am correct the issue is that I as trying to set the Masterpage on a view that didn't have/need a Masterpage. I think that the result was that I was setting a path to a Masterpage and even though that Masterpage exists the View was not expecting it and through an error.
When I updated the View to use a Masterpage I was able to pass the name of the Masterpage directly to the View without an error.
Test.aspx:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Charts.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
hello world!
</asp:Content>
The way that I resolved this in my custom ViewEngine was to check if the current View is a ChildAction.
if (String.IsNullOrEmpty(masterName) && !controllerContext.IsChildAction)
{
masterName = "site";
}

Resources