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>
Related
Hi i want to change the Page redirection in webconfig programmatically.
i have following code in web config.
<location path="WebForm2.aspx">
<system.webServer>
<httpRedirect enabled="true" destination="http://google.com" httpResponseStatus="Permanent" />
</system.webServer>
</location>
i want to enable or disable the httpredirect programmatically using c#.
please suggest me how to do this.
I've tried the code suggested by Rahul but I wasn't able to change the <location> element of the Web.config programatically.
As an alternative you could write an HttpHandler to intercept the request to the WebForm2.aspx page and redirect the user to another URL:
Handler:
namespace StackOverflowHelp
{
public class RedirectHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
Uri uri = context.Request.Url;
if (uri.AbsolutePath == "/WebForm2.aspx.aspx")
context.Response.Redirect("http://google.com");
}
}
}
Handler registration in the Web.config:
<system.webServer>
<handlers>
<add verb="*" path="WebForm2.aspx"
name="RedirectHandler"
type="StackOverflowHelp.RedirectHandler"/>
</handlers>
I tried to do all the possible solutions but still could not get the right answer. Below is my code:
WebApiConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using System.Net.Http.Headers;
namespace WebAPI
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
//test
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Routes.MapHttpRoute(
name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
routeTemplate: "institute/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//change xml to JSON output
// config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
}
}
StudentController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Description;
using WebAPI;
namespace WebAPI.Controllers
{
public class StudentsController : ApiController
{
private InstituteEntities db = new InstituteEntities();
// GET: api/Students
public IQueryable<Student> GetStudents()
{
return db.Students;
}
// GET: api/Students/5
[ResponseType(typeof(Student))]
public IHttpActionResult GetStudent(int id)
{
Student student = db.Students.Find(id);
if (student == null)
{
return NotFound();
}
return Ok(student);
}
// PUT: api/Students/5
[ResponseType(typeof(void))]
public IHttpActionResult PutStudent(int id, Student student)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != student.Id)
{
return BadRequest();
}
db.Entry(student).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!StudentExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Students
[ResponseType(typeof(Student))]
public IHttpActionResult PostStudent(Student student)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Students.Add(student);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (StudentExists(student.Id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = student.Id }, student);
}
// DELETE: api/Students/5
[ResponseType(typeof(Student))]
public IHttpActionResult DeleteStudent(int id)
{
Student student = db.Students.Find(id);
if (student == null)
{
return NotFound();
}
db.Students.Remove(student);
db.SaveChanges();
return Ok(student);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
private bool StudentExists(int id)
{
return db.Students.Count(e => e.Id == id) > 0;
}
}
}
Web.config
<?xml version="1.0" encoding="utf-8"?>
<!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=301879 -->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<appSettings></appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/>
<!-- ADD THIS -->
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
<connectionStrings>
<add name="InstituteEntities" connectionString="metadata=res://*/Institute.csdl|res://*/Institute.ssdl|res://*/Institute.msl;provider=System.Data.SqlClient;provider connection string="data source=BPWSVR01;initial catalog=Institute;persist security info=True;user id=sa;password=sa;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
my Error is below:
{
"$id": "1",
"Message": "An error has occurred.",
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": null,
"InnerException": {
"$id": "2",
"Message": "An error has occurred.",
"ExceptionMessage": "The ADO.NET provider with invariant name 'System.Data.SqlClient' is either not registered in the machine or application config file, or could not be loaded. See the inner exception for details.",
"ExceptionType": "System.ArgumentException",
"StackTrace":" at System.Data.Entity.Infrastructure.DependencyResolution.DefaultProviderFactoryResolver.<GetService>b__0(ArgumentException e, String n)
at System.Data.Entity.Infrastructure.DependencyResolution.DefaultProviderFactoryResolver.GetService(Type type, Object key, Func`3 handleFailedLookup)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Data.Entity.Infrastructure.DependencyResolution.RootDependencyResolver.GetService(Type type, Object key)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Data.Entity.Infrastructure.DependencyResolution.CompositeResolver`2.GetService(Type type, Object key)
at System.Data.Entity.Infrastructure.DependencyResolution.DbDependencyResolverExtensions.GetService[T](IDbDependencyResolver resolver, Object key)
at System.Data.Entity.Core.EntityClient.EntityConnection.ChangeConnectionString(String newConnectionString)
at System.Data.Entity.Internal.LazyInternalConnection.InitializeFromConnectionStringSetting(ConnectionStringSettings appConfigConnection)
at System.Data.Entity.Internal.LazyInternalConnection.TryInitializeFromAppConfig(String name, AppConfig config)
at System.Data.Entity.Internal.LazyInternalConnection.Initialize()"
}
}
Look at the inner exception:
The ADO.NET provider with invariant name 'System.Data.SqlClient' is either not registered in the machine or application config file
It is evident that your issue is related to Entity Framework: you are not deploying correctly System.Data.SqlClient assembly to your server.
Those questions may help you find how to solve this issue:
Entity Framework ADO.NET Sql.Data.Client provider not found
ADO.NET provider with invariant name 'System.Data.SqlClient;' cannot be found (Entity Framework MVC)
I have made a custom Role Provider. Before I updated my VS and NuGet packages everything seemed to work. However, when I login now it looks like the pages gets refreshed (or the View is reloaded atleast). I do see a cookie is created though, but I will not get redirect to Index. Why?
In my Web.Config:
<authentication mode="Forms">
<forms loginUrl="~/Home/Login" timeout="2880" />
</authentication>
<roleManager defaultProvider="MyRoleProvider">
<providers>
<add name="MyRoleProvider" type="project.Authorisation.CustomRoleProvider" />
<remove name="MySQLRoleProvider" />
<add name="MySQLRoleProvider" type="MySql.Web.Security.MySQLRoleProvider, MySql.Web, Version=6.9.6.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" connectionStringName="LocalMySqlServer" applicationName="/" />
</providers>
</roleManager>
In my HomeController:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(User user)
{
if (ModelState.IsValid)
{
bool authenticated = userDBController.isAuthorized(user.Nickname, user.Password);
if (authenticated)
{
FormsAuthentication.SetAuthCookie(user.Nickname, false);
return Redirect(Url.Action("Index", "Home"));
}
else
{
ViewBag.Message = "Inlog data is incorrect!";
return View();
}
}
else
{
return View();
}
}
[Authorize(Roles = "ADMIN")]
public ActionResult Index()
{
return View();
}
So when I logged in I cannot go to Home/Index, it will redirect me to Login anyways. Same for after logging in.
My Custom RoleProvider is quite simple right now:
public class CustomRoleProvider : RoleProvider
{
private MainController mainController = MainController.Instance;
private UserDBController userDBController = MainController.Instance.GetUserDBController();
public override string[] GetRolesForUser(string username)
{
return userDBController.getRollen(username);
}
Before everything, this all worked (also the authorization).
Well I finally found out what was the issue!
Appearently after reinstalling packages and what not my web.config was changed. All I had to do is add enabled="true" to the roleManager section. Therefore the code should look like:
<roleManager defaultProvider="MyRoleProvider" enabled="true">
<providers>
<add name="MyRoleProvider" type="project.Authorisation.CustomRoleProvider" />
</providers>
</roleManager>
So appearently the rolemanager is disabled.
I hope this will help other people who might experience this problem!
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.
My sitemap is at: http://localhost/scirranew/sitemap.ashx
<%# WebHandler Language="C#" Class="SiteMap" %>
using System;
using System.Web;
public class SiteMap : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/xml";
}
public bool IsReusable {
get {
return false;
}
}
}
As far as I know, google will be OK with this. But I would like it to be a .xml filetype for consistency throughout my site.
I've tried rewriting the URL:
<rewrite url="^~/Sitemap.xml" to="~/SiteMap.ashx" processing="stop"/>
But this doesn't work with the .xml extension.
Instead of using an ashx file, just put the code in an assembly and register the handler in web.config with any extension you like:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="Sitemap.xml"
type="SiteMap, AssemblyContainingClass" />
</httpHandlers>
</system.web>
</configuration>