Problem with MVC3 AllowHtml attribute - asp.net-mvc-3

I have a web app based on MVC3 (no beta or release candidate, RTM/RTW version) that has an action that accepts XML files for processing.
Of course, this seems evil to MVC because of possible attacks, so it doesn't allow it. Well, I try to put either AllowHtml on the model object as such:
public class XMLModel
{
[AllowHtml]
public string msg { get; set; }
}
Or I set ValidateInput to false on my action method such as this:
[ValidateInput(false)]
public ActionResult AddCDR(XMLModel model)
{
}
The reason for having a "strongly" typed model in the first place was that I originally tried to have a string value named "msg" as the action method parameter, but that always came back empty.
Now, when someone posts to this form, either on the same machine or from a networked computer, the msg field is always blank.
I have verified with WireShark that the data is actually in the request.
Now, one interesting thing. This should not be necessary with MVC 3. Yet it makes a slight difference.
If I add this to my web config:
<httpRuntime requestValidationMode="2.0" />
It works for requests originating from the local computer, but it does NOT work from another system.
I think the AllowHtml version seems elegant - if only it worked.
I have also found out about a bug in RC2 - again, this should not affect me, but I tried to add the following in Application_Start() anyway:
ModelMetadataProviders.Current = new DataAnnotationsModelMetadataProvider();
As expected, it makes no real difference.
Everything works as expected on my development computer (Win7x64, VS2010), but on the target system (Win2008R2x64, IIS7.5) the above problems are giving me a hard time.
Very important point to note: If I post to the action with no angle brackets, I get the form data as expected. As soon as the angle brackets show up, though, either my action isn't called at all, or it doesn't find the form data, neither in action method parameters or in for instance Request.Params["msg"] where it should be.
Any ideas to allow the XML through?
UPDATE
I've tried to work my way around this while waiting for anyone to come up with an answer here. I have not been able to solve it yet, but I have checked a few additional details;
First, I verified that the ASP.NET MVC 3 version installed on both my development computer and on the web server is the same; v3.0.20105.0 (according to Add/Remove programs).
The web application was actually created with the MVC3 beta, then converted to RC1 and RC2 as they came out, and finally to the RTM version. This meant I had to modify some code because of the ViewBag change. However, since I didn't know exactly what else had changed, I created a brand new MVC3 application with the RTM version, created a controller by the same name, with the same action method, taking a model object similar to the currently used one, renamed the old web app directory and put this new one in place. Exactly the same thing happens - i.e. the parameter with the AllowHtml attribute comes through with all content when the request is made from the local machine, but if it comes from a remote machine, then the HTML (XML actually) is stripped out.
There is no exception. I've installed Elmah and verified this - no exception occurs, my action method is apparently just called with anything looking like XML stripped out from the parameters to the method.
Needless to say, this is driving me crazy. I had some advice yesterday to look at the source code of MVC3, but unfortunately that doesn't really help me, as I can't see anything obviously wrong there, and I can't debug code on the server in question.
Any insights still highly desired, thanks! :)

I cannot reproduce this.
Model:
using System.Web.Mvc;
namespace MvcApplication3.Models {
public class XmlModel {
[AllowHtml]
public string msg { get; set; }
}
}
Controller:
using System.Web.Mvc;
using MvcApplication3.Models;
namespace MvcApplication3.Controllers {
public class HomeController : Controller {
public ActionResult Index() {
return View();
}
[HttpPost]
public ActionResult Index(XmlModel model) {
return View();
}
}
}
View:
#model MvcApplication3.Models.XmlModel
#using (Html.BeginForm()) {
<div class="editor-label">
#Html.LabelFor(model => model.msg)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.msg)
#Html.ValidationMessageFor(model => model.msg)
</div>
}
These were added to a default empty MVC 3 project. Everything posts fine. When I remove [AllowHtml], it generates the appropriate error message.

I am answering this myself because this was an obscure situation, and MVC3 was not the problem.
The system that POSTed data to my application was doing so with malformed data. In addition to that, I was told that they were also POSTing to an older MVC2 application that worked just fine - this was wrong, it turned out they were GETting in that case, and GET they happen to do correctly.
If anything, fairly thorough testing has confirmed that the AllowHtml attribute actually works very well. Never trust your input, tho. :)

Related

Error trying to scaffold a view in ASP.NET Core 6.0 MVC

I'm trying to scaffold a new razor view using Visual Studio. I select a template, my model and my DbContext, then I get the error message shown below.
Things to note. My models, my DbContext and my website are all in different projects. From the message below I am using AddDbContext and I have a constructor that accepts a DbContextOptions<TContext> parameter.
I read a comment on a blog post that the issue is because my context is in another project. The comment referenced something about the need to inject the Configuration into the DbContext to get the connection string and manually add it in the OnConfiguring override.
I can't find any examples if this is correct or how to set it up. Any help would be appreciated.
EDIT:
Testing out the theory from the blog comment I mentioned above, I added this section into my DbContext. ConnectionString is a hardcoded string constant with my connection information. This does work and allow me to scaffold, so the question still remains. How can I inject this connection string into my DbContext to allow the scaffolding to work?
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(ConnectionString);
}
else
{
base.OnConfiguring(optionsBuilder);
}
}
EDIT: So after making this change, I checked in the code and had another developer pick it up. It appears this section above just needs to be there to allow scaffolding to work. He never changed the connection string to point to his environment. He no longer got the error above it just worked.
I am not sure about what is the actual problem but it seems like we were having problems creating DbContext at design time. I manually added the code below and it's working now. It's just a temporary solution tho.
public AppDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=JwtTemplate;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False");
return new AppDbContext(optionsBuilder.Options);
}
Reference: https://stackoverflow.com/a/70559350

Model Validation using Data Annotations not working on Mac VS.NET

I created a new Web API Application on MacOS with VS.NET. I added a model with the following code:
public class PersonAddRequest {
[Required]
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then I created a Web API Controller like so:
[Route("api/[controller]")]
[ApiController]
public class PeopleController : ControllerBase {
[HttpPost]
public IActionResult Post(PersonAddRequest model) {
return base.Ok(model);
}
}
When using PostMan I post JSON as so (note firstName is missing):
{
"lastName":"McDonalds"
}
When I run this code on a Web API Application created on a Windows OS validation works as expected. However, when I create the project in MacOS validation doesn't work.
When I create the project in Windows OS then open and run it on MacOS, validation works!
So my question, is this a feature that is missing as part of the scaffolding on VS.NET for Mac?
You require the FromBody attribute for the body argument:
[Route("api/[controller]")]
[ApiController]
public class PeopleController : Controller
{
[HttpPost]
public IActionResult Post([FromBody]PersonAddRequest model)
{
return Ok(model);
}
}
This is required for model validation.
Here's an example git repo using this form of model validation that is confirmed working on MacOS Mojave 10.14.4
I want to thank #nelsontruran for helping me explore VS.NET on Mac. I'm actually running a later version of the Mac (10.14.5 Mojave). However, the version had nothing to do with the original problem.
Thru the patients and persistent help of #nelsontruran I recreated the project but instead of using the suggested templates I dug around a little for the correct application (don't trust the suggested applications in VS.NET). Here's the step-by-step instructions on how to create an API that automatically performs model validation:
Open VS.NET for Mac
Create a new project
When prompted to "Choose a template for your new project", select "App" under the ".Net Core" section on the left side pane.
On the right side pane, select API
From there you can review #nelsontruran's example on git to see the magic of Model Validation.
I believe I might have been choosing "Web Application" thinking that it would be the same in Mac as it is in Windows.
A simple oversight on my part. I hope this helps someone who was confused and struggling like me.
Thank you again to #nelsontruran!!!

ASP.NET Output Caching not working after upgrade from MVC2 to MVC4

We have an existing MVC2 project that we just upgraded to MVC4 following first these steps to get to MVC3, then these steps to get to MVC4.
Output caching had been successfully working for a long time in our MVC2 project, but it does not work after the MVC4 version.
I've added a simple controller to test caching:
public class TestController : Controller
{
[OutputCache(Duration = 600, VaryByParam = "*")]
public ActionResult CacheTest()
{
return Content(DateTime.Now.ToLongTimeString());
}
}
Each time i refresh this page, the time output to the browser changes.
Creating a new MVC3 project in this same solution, then upgrading to MVC4, then copying this same code over works as expected.
So there must be something somewhere in our existing code or configuration that is breaking output caching.
I've also tried stripping out a ton of stuff from the web.config file thinking something there was causing problems - no luck.
Any suggestions on how to fix or debug this?
UPDATE:
Rendering the CacheTest action above in any view will display cached results - i.e. the date does not change on each refresh:
<% Html.RenderAction("CacheTest", "Test"); %>
Why does that work, but the action url from a browser is never cached?
Turns out this was an issue with a third party library - 51Degrees. This was an issue introduced into a recent version of this library. In the process of converting from MVC2 to MVC4 I installed the nuget package which was a few versions later than the previous version I was using.
False alarm - nothing to do with the ASP.NET MVC upgrade or anything ASP.NET related.

ASP.NET MVC 3 Site Loading Is Extremely Slow

I really don't know where to begin with this question, but the site I'm working on at times has some really slow page loads. Especially after doing a build, but not always. I usually have to refresh the page 5-10 times before it actually comes up. I guess I am trying to see where exactly I should begin to look.
ASP.NET MVC 3
Ninject
AutoMapper
Entity Framework Code First 4.1
SQL Server 2008
Razor
UPDATES
Concerning some of the questions, it can do this long loading on every page, but after it loads its fairly quick on all the pages.
After posting this and getting your replies I started the application and it is still loading and probably won't ever load unless I click reload on the browser.
No caching, and the EF models aren't huge.
I am using Razor and Visual Studio 2010 with 6 GB of memory and an I7 processor.
I am using IIS Express and the default web server when debugging. It also does this on IIS7 on the main server.
I may look into the MVC Profiler and Glimpse to see what I can find.
Below I have some code this runs when it hits the homepage. I would say it never loads when I first start up the server. I put a break point at var model which never gets hit. If I reload the page then it does.
public ActionResult Index()
{
var model = new HomeViewModel();
model.RecentHeadlines = _headlineService.GetHeadlines(1, Config.RecentHeadlinesPageSize, string.Empty);
return View(model);
}
Below is my datacontext setup also.
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private DataContext _dataContext;
public DataContext Get()
{
return _dataContext ?? (_dataContext = new DataContext());
}
protected override void DisposeCore()
{
if (_dataContext != null)
_dataContext.Dispose();
}
}
public class Disposable : IDisposable
{
private bool isDisposed;
~Disposable()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!isDisposed && disposing)
{
DisposeCore();
}
isDisposed = true;
}
protected virtual void DisposeCore()
{
}
}
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabaseFactory _databaseFactory;
private DataContext _dataContext;
public UnitOfWork(IDatabaseFactory databaseFactory)
{
_databaseFactory = databaseFactory;
}
protected DataContext DataContext
{
get { return _dataContext ?? (_dataContext = _databaseFactory.Get()); }
}
public void Commit()
{
DataContext.Commit();
}
}
I'd start by checking what the timeouts are set to in IIS for the process to be recycling itself.
I'm also a very big fan of the MVC Mini-Profiler which could show you exactly how long various parts of your page load are taking, definitely take a look at it.
Edit:
It is worth noting that the Glimpse project is also great for this task these days.
Sounds like it might be an issue with IIS AppPool recycling if you're experiencing it after builds or after periods of inactivity.
To help with AppPool timeouts you can utilize a batch file I created to help mitigate the issue.
That won't solve the problem for you after new builds because your ASP.NET MVC application needs to be JIT-compiled upon first run. If you're really eager to eliminate that issue, you can use ASP.NET precompliation.
Try Glimpse or use ASP.NET Tracing.
You could also precompile your views if you are using the Razor view engine via Razor Single File Generator for MVC.
It depends on what happened in your previous run, sometimes if you throw an error and don't clear that out then you will have issues running the application. It helps to restart the browser every time you build if there was an error.
However, this could be an issue of caching. It is possible that your database is caching due to poorly maintained context disposing. This would cause the lookups to run faster and faster as they were encountered in pages. Make sure you always call .dispose() when done with your database transactions.
funny - I've noticed something similar once with unity and mvc but the problem I believe resolved itself. You could also try ants profiler to see if the problem is outside of MVC.
If you let a single request sit there (without requesting 5+ times) what happens?
Let a single request run - is ANY of your code hit? (setup logging log4net, nlog, etc) to run application_start, etc to see if any code is getting called after the compile.

Deploying Asp.Net MVC 2 /C# 4.0 application on IIS 6

I got a problem migrating from VS.Net 2008 / MVC 1 to VS.NET 2010 (+C# 4.0) / MVC 2
The web.config has been updated, the site runs well in Cassini, but my problem now is deploying on IIS 6.
I updated the web site to run using ASP.Net 4,
but whatever URL I try, I always have a 404 error. It's as if the routing was not taken into account (yes, the wildcard mapping has been done).
I do not understand this mess and could not google anything interesting...
Thanks for your suggestions !
Ok I got y answer (thanks to a colleague)
When migrating from ASP.Net 2.0 to ASP.Net4.0,
if you meet the same problem,
then check in Web Service Extension if ASP.Net v4 is Allowed.
In my case, after installing the .Net framework 4, it was prohibited.
Will & Mark : thanks for your help, hope it will helps others.
I think I know what's happening: on IIS6, as well as the wildcard mapping you will need a default document (Default.aspx) that routes folder requests to the MVC handler.
There was one included with the MVC1 project templates, but it has been removed in MVC2.
Default.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="YourNameSpace._Default" %>
<%-- Please do not delete this file. It is used to ensure that ASP.NET MVC is activated by IIS when a user makes a "/" request to the server. --%>
and Default.aspx.cs:
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
namespace YourNameSpace
{
public partial class _Default : Page
{
public void Page_Load(object sender, System.EventArgs e)
{
// Change the current path so that the Routing handler can correctly interpret
// the request, then restore the original path so that the OutputCache module
// can correctly process the response (if caching is enabled).
string originalPath = Request.Path;
HttpContext.Current.RewritePath(Request.ApplicationPath, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext.Current);
HttpContext.Current.RewritePath(originalPath, false);
}
}
}
When you say "It's as if the routing was not taken into account", I suspect that it actually isn't, and this is your problem.
This finally fixed it for me:
I commented earlier, and a wee bit prematurely. My comment to Mark B's post was getting my initial Index view to show up, but then I kept getting the 404 errors whenever I navigated to any other view.
I was also distracted by the green check mark approved solution in this particular forum, but I could not even see the web server extensions folder in IIS 6 on my desktop; therefore, I had no control from that stand point of enabling aspnet 4.0, though I made sure it was installed by performing running the following command line:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319> aspnet_regiis -i
Now for the actual piece that finally allowed me to navigate to the other views besides just my Home/Index:
In the Global.asax.cs file of your VS 2010 Solution, you will see code as follows in the RegisterRoutes method:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
I simply added ".aspx" after the {action} section of the tag as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}.aspx/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
And ahla wahla Peanut Butter and Jelly sandwiches. :0)
If you want to do it in C#, just add the System.DirectoryServices reference and this piece should do the job nicely.
DirectoryEntry w3svc = new DirectoryEntry("IIS://localhost/W3SVC");
w3svc.Invoke("EnableWebServiceExtension", "ASP.NET v4.0.30319");
w3svc.CommitChanges();
HTH

Resources