I have a Repository Project that is added to my MVC application.
Within my C# code, of the MVC Web App, I have had to add a reference to System.Data.Entity so that I can access the objects from my Repository.
So the following fails if I do not have the reference added;
DataRepository<Store> repo = new DataRepository<Store>();
List<Store> allSorted = repo.All(x => x.name);
Now I want to pass that list to my Partial View, which sits within a FVM and it's the FVM that I pass to the Partial View.
So the index.aspx code;
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<StoresFVM>" %>
<% Html.RenderPartial("StoreList", Model.StoreListFVM); %>
And the ASCX code;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<StoreListFVM>" %>
<%
SelectList storeList = new SelectList(Model.Stores.Select(x => new { Value = x.number, Text = x.name }),"Value","Text");
%>
<%= Html.DropDownList("SelectedStore", storeList) %>
However, I get an error informing me that I need to include a reference to System.Data.Entity in the ascx. I don't get why for one.
I have tried adding the namespace to the web.config file and I have tried importing the namespace at the top of the ascx page.
Thoughts?
EDIT
\nasfile02\Visual Studio
2010\Projects\TOM\TOM\Views\Stores\PartialViews\StoreList.ascx(4):
error CS0012: The type 'System.Data.Objects.DataClasses.EntityObject'
is defined in an assembly that is not referenced. You must add a
reference to assembly 'System.Data.Entity, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089'.
EDIT
namespace TOM.FormViewModels
{
public class StoresFVM
{
public StoreListFVM StoreListFVM { get; set; }
}
}
namespace TOM.FormViewModels
{
public class StoreListFVM
{
public List<Store> Stores { get; set; }
}
}
You should make sure the web.config looks as following:
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
Also described at: https://stackoverflow.com/a/3611040/1737862
Related
The abstract problem: I'm trying to limit user input in text fields to the same as the database length of the column. So I want to set a maxlength attribute on an html input, and the maxlength should be the same as the max length allowed in the database. I could hardcode these constants throughout the frontend, but I'm trying to set that value dynamically.
The problem: telerik RadComboBox won't accept an asp code block to set a property. The exception is as follows:
Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
Parser Error Message: Cannot create an object of type 'System.Int32' from its string representation '<% Utility.GetColumnMaxLength<Portfolio>(x => x.Title) %>' for the 'MaxLength' property.
I've created a new minimal asp.net project to duplicate the problem. default.aspx source (no .cs code behind):
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TelerikCodeBlock._Default" %>
<%# Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<%# Import namespace="TelerikCodeBlock" %>
<%# Import namespace="TelerikCodeBlock.DataModel" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<telerik:RadComboBox ID="txtboxTitle" runat="server" MaxLength="<% Utility.GetColumnMaxLength<Portfolio>(x => x.Title) %>" >
</telerik:RadComboBox>
</asp:Content>
The Utility class has been minimized to the following
namespace TelerikCodeBlock
{
public class Utility
{
public static int GetColumnMaxLength<T>(Expression<Func<T, object>> property)
{
// looks at Entity Framework metadata in real project ...
return 3;
}
}
}
Data model looks like
namespace TelerikCodeBlock.DataModel
{
public class Portfolio
{
public int Id { get; set; }
public string Title { get; set; }
}
}
Possible workaround: using ASP.NET Expressions (the <%$ ... %> code blocks), build a general expression that executes code, as outlined here.
Add a reference to Microsoft.CodeDom.Providers.DotNetCompilerPlatform.
Define the following somewhere:
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Compilation;
using System.Web.UI;
namespace TelerikCodeBlock
{
[ExpressionPrefix("Code")]
public class CodeExpressionBuilder : ExpressionBuilder
{
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
object parsedData, ExpressionBuilderContext context)
{
return new CodeSnippetExpression(entry.Expression);
}
}
}
And register it in the web.config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" >
<expressionBuilders>
<add expressionPrefix="Code" type="TelerikCodeBlock.CodeExpressionBuilder"/>
</expressionBuilders>
</compilation>
...
Now change the asp control to use the expression code block:
<telerik:RadComboBox ID="txtboxTitle" runat="server" MaxLength="<%$ Code: Utility.GetColumnMaxLength<Portfolio>(x => x.Title) %>" >
I am very new to ASP.NET MVC4 and am taking a course on the topic. I have a very minor issue with error handling. When the instructor adds <customErrors mode = "On"/> to the web.config file in the <system.web> tag, he is redirected to the friendly error page (instead of the stack trace).
When I make this change, I am still directed to the stack trace "yellow page of death".
Since I am making a concerted effort to understand this as thoroughly as possible, I thought I'd ask here. Why does turning <customErrors mode="On"/> work for the instructor and not me?
Here is my <system.web> tag:
<system.web>
<customErrors mode="On"/>
<httpHandlers>
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
And here is my Global.asax.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace OdeToFood
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
}
}
And finally, my FilterConfig.cs
using System.Web;
using System.Web.Mvc;
namespace OdeToFood
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
}
I currently have the default view Error.cshtml.
I also tried
<customErrors mode="On" defaultRedirect="Error"/>
and
<customErrors mode="On" defaultRedirect="~/Error.cshtml"/>
I am using this code to force the error:
public class CuisineController : Controller
{
//
// GET: /Cuisine/
public ActionResult Search(string name = "french")
{
throw new Exception("Something terrible has happened");
var message = Server.HtmlEncode(name);
return Content(message);
}
}
}
As you can tell, I'm very new to this so my apologies if this is a frivolous question but I am trying to learn as best I can.
You still need to make an error page. For example,
Web.config
<system.web>
...
<customErrors defaultRedirect="~/Common/Error" mode="On"/>
</system.web>
CommonController
public class CommonController : Controller
{
// Error
public ActionResult Error()
{
this.Response.StatusCode = 503;
this.Response.TrySkipIisCustomErrors = true;
return View();
}
}
~/Views/Shared/Error.cshtml
#{
ViewBag.Title = "Error";
}
<h2>#ViewBag.Title</h2>
<p>
Error ...
</p>
I've been digging around for a while now trying to figure out how to use my custom AuthorizeAttribute class in my view to show and hide links. I'm transitioning from IsInRole to the custom AuthorizeAttribute because I want the end user to select which groups are authorized to perform certain tasks. Up to this point I've been using:
#{ if (HttpContext.Current.User.IsInRole("UserMgr"))
{ Html.ActionLink("Edit", "Edit", new { id = item.pkRecID }); }
}
Where UserMgr is a domain group. (this does work but is not what I need to do)
I then created a custom AuthorizeAttribute class:
public class isAuthorized : AuthorizeAttribute
{
public string Access { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
string[] aszList = Access.Split(',');
if (!authorized)
{
// The user is not authenticated
return false;
}
var user = httpContext.User;
if (user.IsInRole("Admin"))
return true;
var rd = httpContext.Request.RequestContext.RouteData;
var id = rd.Values["id"] as string;
if (string.IsNullOrEmpty(id))
{
// Now id was specified => we do not allow access
return false;
}
foreach (string szGroup in aszList) // check to see if user is in group
{
if (user.IsInRole(szGroup))
{
return true;
}
}
return false;
}
This works in my controller to block access to functions but how do I hide links in my views using this function?
Thanks!
You could create an extension method, so you can apply it on the MvcHtmlStrings in your Cshtml file
Example:
public static IHtmlString If(this IHtmlString value, bool evaluation)
{
return evaluation ? value : MvcHtmlString.Empty;
}
Then on your html Element you can use it like this:
#Html.ActionLink("Reports", "Index", "Report").If(User.IsInRole("SuperAdmin"))
UPDATE
Steps:
Create a new static class in your project.
Add the suggested extension method to the newly created class.
To make this static class available in all cshtml views go to the webconfig located in the Views folder.
Again pay attention so that the web config is in the views folder, do NOT edit the one thats at the root of your app.
There add the namespace where your static class is located just like in the example below.
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="YourApplication.Utils"/> <!-- THIS IS THE EXAMPLE ON HOW TO INSERT THE NAMESPACE THAT CONTAINS YOUR STATIC CLASS -->
<add namespace="Microsoft.Web.Helpers"/>
</namespaces>
</pages>
</system.web.webPages.razor>
I cant explain it better then this.
I'm having trouble accessing the properties of Model inside my view, when it's an IEnumerable type.
My controller code:
//
// GET: /Home/
public ActionResult Index()
{
List<CourseworkQuestion> courseworkQuestions = repository.GetCourseworkQuestions(repository.GetUsername()).ToList();
List<HomeViewModel> model = new List<HomeViewModel>();
foreach (CourseworkQuestion courseworkQuestion in courseworkQuestions)
{
HomeViewModel hvm = new HomeViewModel(courseworkQuestion);
model.Add(hvm);
}
return View(model);
}
And in my view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<InternalAssessmentViewer.ViewModels.HomeViewModel>>" %>
I'm sure I've done this before, but I'm not sure if I'm missing something obvious.
You need to include a using to get the System.Collections.Generic namespace in your page:
<%# Import namespace="System.Collections.Generic" %>
<%# Import namespace="System.Linq" %> //To get all the LINQ extension methods
Or fully qualify the reference to IEnumerable<T>:
System.Web.Mvc.ViewPage>
I'm trying to get my content page to be able to access an ASP:Literal on a master page.
I have my content page as:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="viewProduct.aspx.cs" Inherits="AlphaPackSite.viewProduct" Title="Hi there!" %>
<%# MasterType TypeName="Main" %>
Then my master page called Main.master has:
<asp:Literal runat="server" ID="lblBasket" />
But from the content page when I try and do:
Master.basket.Text = "test";
I get:
Error 46 The type or namespace name
'Main' could not be found (are you
missing a using directive or an
assembly reference?)
The error is on the designer page:
public new Main Master {
get {
return ((Main)(base.Master));
}
}
My master page code behind is:
namespace AlphaPack.MasterPages
{
public partial class Main : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
this.IsLoggedIn = Request.IsAuthenticated;
}
public bool IsLoggedIn
{
get { return this.ViewState["isLoggedIn"] as bool? ?? false; }
set { this.ViewState["isLoggedIn"] = value; }
}
}
}
Is the designer within your AlphaPack.MasterPages namespace?
The MasterType isn't fully qualified, should it be? Don't you have to provide a path as well? (Not familiar with, sorry).
How does this respond if you use a MasterPageFile reference instead of a MasterType?
<%# Page Language="C#" MasterPageFile="~MasterPages/Main.Master" AutoEventWireup="true" CodeBehind="viewProduct.aspx.cs" Inherits="AlphaPackSite.viewProduct" Title="Hi there!" %>
<%# Page MasterPageFile="~/MasterPages/Main.master" .. %>
<%# MasterType VirtualPath="~/MasterPages/Main.master" .. %>
Okey, that's how it looks in my own app:
Master page (Site.master, in the root):
<%# Master Language="C#" AutoEventWireup="True" CodeBehind="Site.master.cs" Inherits="Project.SiteMaster" %>
It's code-behind:
namespace Project
{
public partial class SiteMaster : System.Web.UI.MasterPage { }
}
Content page (Test.aspx, in the root):
<%# Page Language="C#" AutoEventWireup="True" CodeBehind="Test.aspx.cs" Inherits="Project.Test" MasterPageFile="~/Site.master" Title="Test" %>
it's code-behind:
namespace Project
{
public partial class Test : System.Web.UI.Page { }
}
That's how auto-generated code looks like:
namespace Project {
public partial class SiteMaster {
/// <summary>
/// lblBasket control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal lblBasket;
}
}
So create a property but don't share the control itself, only text:
public string BasketText
{
get { return this.lblBasket.Text; }
set { this.lblBasket.Text = value; }
}