While developing an admin-page in MVC I kept getting the old "Potentially dangerous Request..." which occurs when trying to submit form data including html tags.
After adding the "validateRequest=false" to the pages-element in web.config (which turns this feature off in asp.net webforms) and checking that the page directive didn't ovveride this setting I was getting quite annoyed that I still got the exception on my page.
However - in MVC you need to set an attribute on your action in the controller to turn off validation:
[ValidateInput(false)]
public ActionResult Edit(int id, FormCollection collection)
{}
In my opionon I think that the setting is web.config should be read by the MVC actions as well as you otherwise need to define this attribute on all actions that might include html as a string parameter.
fredag 27 februari 2009
tisdag 17 februari 2009
JavaScript context binding
One of the neatest features in the JavaScript library Prototype is its helper function for context binding. This is one feature to which I have yet to find the correspondence in jQuery. The following code is the functional equivalent of the Prototype solution, which I've found use for too many times:
This solves a common JavaScript problem, when working with callback functions. Consider the following:
For added value, bind also comes with the option to specify additional arguments to be passed along to the function, as it is being invoked. To demonstrate why this is useful, consider the following scenario:
<script type="text/javascript">
Function.prototype.bind = function(context)
{
var __method = this;
var __args = new Array();
for(it = 1; it < arguments.length; it++)
__args.push(arguments[it]);
return function() {
for(ait = 0; ait < arguments.length; ait++)
__args.push(arguments[ait]);
__method.apply(context, __args)
};
}
</script>
So what does it do? Well, it makes sure that all functions will have a function of their own, called bind. Bind receives a context, and makes sure that the function is always invoked from that context - i.e. that the "this." notation in the function will always reference the given context.Function.prototype.bind = function(context)
{
var __method = this;
var __args = new Array();
for(it = 1; it < arguments.length; it++)
__args.push(arguments[it]);
return function() {
for(ait = 0; ait < arguments.length; ait++)
__args.push(arguments[ait]);
__method.apply(context, __args)
};
}
</script>
This solves a common JavaScript problem, when working with callback functions. Consider the following:
function User(username, password)
{
this.username = username;
this.password = password;
this.tryLogin = function()
{
$.ajax({
type: "POST",
url: "Default.aspx/Login",
...
success: function(msg)
{
if(msg == 'true')
alert('Welcome '+this.username);
}
}
}
In the above code, the function passed along as a callback will be called from the jQuery AJAX handler, hence "this.username" will look for a username property in $.ajax() (and presumably fail to find one). Now, if we had included the snippet at the top of this entry, we would've been able to modify the callback declaration to the following:{
this.username = username;
this.password = password;
this.tryLogin = function()
{
$.ajax({
type: "POST",
url: "Default.aspx/Login",
...
success: function(msg)
{
if(msg == 'true')
alert('Welcome '+this.username);
}
}
}
success: function(msg)
{
alert('Welcome '+this.username);
}.bind(this);
Here, instead of passing in assigning the success property with function x, we're passing x to bind, and assigning the value that bind returns, which is x hooked up to a specified context (this, as passed to bind).{
alert('Welcome '+this.username);
}.bind(this);
For added value, bind also comes with the option to specify additional arguments to be passed along to the function, as it is being invoked. To demonstrate why this is useful, consider the following scenario:
<button id="btn0">Button0</button>
<button id="btn1">Button1</button>
<button id="btn2">Button2</button>
<script type="text/javascript">
function Person(name) {
this.name = name;
this.logClick = function(x) {
alert(this.name + ' clicked button ' + x);
};
this.start = function() {
for(var i = 0; i < 3; i++)
{
$('#btn'+i).onclick = function() { this.logClick(i) }.bind(this);
}
};
}
var p = new Person('Test');
p.start();
</script>
Now, the start function will hook up the three buttons with onclick events that will trigger the highlighted function. The bind is there, so we will be able to access this.name in logClick without a problem, but our desired effect here - to get Button1, say, to alert "Test clicked button 1" - will still not be met: the i parameter won't be accessed until the actual click event occurs, and by then, the for loop will have completed, and i will have the value of "3". All buttons will produce the same output. What we want, here, is to tell the function to use the value that the variable contained at the time of the event wireup. Again, bind comes to the rescue:<button id="btn1">Button1</button>
<button id="btn2">Button2</button>
<script type="text/javascript">
function Person(name) {
this.name = name;
this.logClick = function(x) {
alert(this.name + ' clicked button ' + x);
};
this.start = function() {
for(var i = 0; i < 3; i++)
{
$('#btn'+i).onclick = function() { this.logClick(i) }.bind(this);
}
};
}
var p = new Person('Test');
p.start();
</script>
$('#btn'+i).onclick = function(x) { this.logClick(x) }.bind(this, i);
The above modification will solve the issue, and produce the desired output. Now that we're binding the parameter in bind, we can, of course, get rid of the delegate entirely:$('#btn'+i).onclick = this.logClick.bind(this, i);
tisdag 30 december 2008
Making the JsonResult in MVC ignore a property
In MVC each controller action returns an "ActionResult". This can be a View, Content (plain text) or JsonResult for example. With JsonResult the output will (obviously) be serialized to JSON.
However - when using any serializeri on classes with bi-directional fields/properties you will run into problems as the serialization will lead to a endless loop trying to follow the bi-directional fields back and forth.
Using other serializer such as an XML serializer for example you just tag the bi-directional property with an "XMLIgnore" attribute and the serializer will basically ignore the field during serialization.
But trying to find a way for the JsonResult was not very easy as there is basically no subjects on this to be found using Google (at this time). However, using Reflector I found that the JsonResult is using the serializer "JavaScriptSerializer" found in "System.Web.Scrtipt.Serializer" (System.Web.Extensions.dll version 3.5). Following the code I found that the attribute to use to ignore a field is "ScriptIgnore" also found in "System.Web.Script.Serialization".
So, problem solved: Use the "ScriptIgnore" attribute to make the Json serializer in MVC ignore your bi-directional fields!
However - when using any serializeri on classes with bi-directional fields/properties you will run into problems as the serialization will lead to a endless loop trying to follow the bi-directional fields back and forth.
Using other serializer such as an XML serializer for example you just tag the bi-directional property with an "XMLIgnore" attribute and the serializer will basically ignore the field during serialization.
But trying to find a way for the JsonResult was not very easy as there is basically no subjects on this to be found using Google (at this time). However, using Reflector I found that the JsonResult is using the serializer "JavaScriptSerializer" found in "System.Web.Scrtipt.Serializer" (System.Web.Extensions.dll version 3.5). Following the code I found that the attribute to use to ignore a field is "ScriptIgnore" also found in "System.Web.Script.Serialization".
So, problem solved: Use the "ScriptIgnore" attribute to make the Json serializer in MVC ignore your bi-directional fields!
onsdag 5 november 2008
SEO-friendly 404 Exceptions
Custom 404 pages is a simple means of approaching a user-friendly experience even in the (albeit rather specific) case of an unhandled exception. In order to take the step from user-friendly to SEO-friendly, however, merely adjusting the customErrors tag in web.config is sub-par.
The problem
Modifying customErrors to redirect a user to a custom 404 page in the case of a fileNotFoundException will do just that - redirect the user - which means taking the detour to the client, informing of the redirect, which in turn means a 302 response from the server, before the user lands at the 404 page. The only implication of this is that search engine will fail to treat the response as a proper 404.
The solution
To resolve the issue, we have to drop the customErrors clause, and invoke Global.asax. Catching all exceptions in Global.asax, we are able to filter out the 404's, and render the appropriate site without tampering with redirects
void Application_Error(object sender, EventArgs e)
{
HttpException ex = Server.GetLastError() as HttpException;
if(ex != null && ex.GetHttpCode() == 404)
{
Response.Clear();
Response.StatusCode = 404;
Response.WriteFile("~/Pages/404.html");
Response.End();
}
}
A brief note on deployment
Finally, when deploying a project with a Global.asax file, from a web deployment project, make sure that the following files are updated:
- PrecompiledApp.config
- bin\App_global.asax.cs
- bin\App_global.asax.cs.compiled
Note that Global.asax is compiled in its entirety, and need not be uploaded to the production environment.
The problem
Modifying customErrors to redirect a user to a custom 404 page in the case of a fileNotFoundException will do just that - redirect the user - which means taking the detour to the client, informing of the redirect, which in turn means a 302 response from the server, before the user lands at the 404 page. The only implication of this is that search engine will fail to treat the response as a proper 404.
The solution
To resolve the issue, we have to drop the customErrors clause, and invoke Global.asax. Catching all exceptions in Global.asax, we are able to filter out the 404's, and render the appropriate site without tampering with redirects
void Application_Error(object sender, EventArgs e)
{
HttpException ex = Server.GetLastError() as HttpException;
if(ex != null && ex.GetHttpCode() == 404)
{
Response.Clear();
Response.StatusCode = 404;
Response.WriteFile("~/Pages/404.html");
Response.End();
}
}
A brief note on deployment
Finally, when deploying a project with a Global.asax file, from a web deployment project, make sure that the following files are updated:
- PrecompiledApp.config
- bin\App_global.asax.cs
- bin\App_global.asax.cs.compiled
Note that Global.asax is compiled in its entirety, and need not be uploaded to the production environment.
torsdag 31 juli 2008
Exlude files and directories when building deploy project
Its quite ezy ®.
- Rightclick the deployment project and click "Open project file".
- Insert the following code (example):
<ItemGroup>
<ExcludeFromBuild Include="$(SourceWebPhysicalPath)\Test\**\*.*"/>
<ExcludeFromBuild
Include="$(SourceWebPhysicalPath)\Images\**\*.*"/>
</ItemGroup>
Done! Now it wont copy all those directories to your release folder, in the long run it will save you a lifetime of waiting.
torsdag 22 maj 2008
LINQ to SQL: On null values in coalesce expressions
The T-SQL function COALESCE is a convenient way of using optional parameters in an SQL query. It accepts a number of parameters, and returns the first non-null value in the set. When all the values in the set are null, the function returns a null value. For those more acquainted with SQL CASE, the following two expressions are exactly identical:
C# provides a convenient shorthand - expr1 ?? expr2 - for coalesce expressions, which allows us to create a function as such:
In LINQ to SQL, the ?? shorthand is always translated into COALESCE when the SQL query is generated, which equips us with the ability to use optional parameters as seen in figure 1:
Figure 1
public IEnumerable- GetItems(int? parentId, int? typeId)
{
myDataContext db = new myDataContext();
return from item in db.Items
where
item.ParentId == (parentId ?? item.ParentId)
&& item.TypeId == (typeId ?? item.TypeId)
select item;
}
As a side-remark, note the necessity of brackets in the above code. This code will render the following SQL query:
So far so good, but this, in fact, poses a problem when using nullable database fields. Consider the following table structure:
Now, assume we want to find all items of TypeId 5, regardless of their parent items; indeed, regardless of whether they have a parent at all. The following request seems intuitive enough: GetItems(null, 5);. This will result in the C# expression item.ParentId == (null ?? item.ParentId), which is completely valid, but it will translate to the following SQL:
For a record of ParentId 1 and TypeId 5, this will be just the way to do things, but if we consider the fact that there could exist an item with ParentId null and TypeId 5, the first COALESCE would return null, as both of its parameters would be of a null value. In SQL, this results in a null = null comparison, which will return false (hence the IS NULL syntax). Consequently, items with a ParentId of null will not be returned, even though the intention was to specify that the query should disregard of ParentId completely.
A workaround for the problem would be to rewrite a method accordingly:
Figure 2
Now, you don't have to look at figure 2 to realize that there's probably a better way to solve this problem. Expression trees would do the trick, for sure, but for our simple implementation, it turns out there's a less complex solution:
Figure 3
Beginning by selecting the entire set of items available, we then proceed to filter the results to match any of the criterias that may or may not be provided. At first glance, this would appear to begin by executing a plain SELECT * FROM Items query, returning all items in the table, even when we know that's not always requested, but as the result set - items - is never enumerated before the return statement, LINQ to SQL optimizes the above code into one query at runtime, depending on what values have been specified.
An SQL Profiler trace gives us the answers in plain text:
Figure 1
The query generated in Figure 1 returns 0 rows, which is not what we expect, given the data in the table.
Figure 2
The query from Figure 2 gives us the result we want, but in a verbose and inconvenient query
Figure 3
From Figure 3, only one query is executed (although we appear to have begun by selecting everything in the table), and only the non-null parameter is passed.
SELECT COALESCE(@param1, @param2, 'Default value')
SELECT
CASE WHEN @param1 IS NOT NULL THEN @param1 ELSE
CASE WHEN @param2 IS NOT NULL THEN @param2 ELSE
'Default value'
END
END
CASE WHEN @param1 IS NOT NULL THEN @param1 ELSE
CASE WHEN @param2 IS NOT NULL THEN @param2 ELSE
'Default value'
END
END
C# provides a convenient shorthand - expr1 ?? expr2 - for coalesce expressions, which allows us to create a function as such:
public int Coalesce(int? var, int defaultValue)
{
return var ?? defaultValue;
}
{
return var ?? defaultValue;
}
In LINQ to SQL, the ?? shorthand is always translated into COALESCE when the SQL query is generated, which equips us with the ability to use optional parameters as seen in figure 1:
Figure 1
public IEnumerable
{
myDataContext db = new myDataContext();
return from item in db.Items
where
item.ParentId == (parentId ?? item.ParentId)
&& item.TypeId == (typeId ?? item.TypeId)
select item;
}
As a side-remark, note the necessity of brackets in the above code. This code will render the following SQL query:
SELECT
*
FROM
Items
WHERE
ParentId = COALESCE(@parentId, ParentId)
AND TypeId = COALESCE(@typeId, TypeId)
*
FROM
Items
WHERE
ParentId = COALESCE(@parentId, ParentId)
AND TypeId = COALESCE(@typeId, TypeId)
So far so good, but this, in fact, poses a problem when using nullable database fields. Consider the following table structure:
Items
-----------------------------------
Field name Type Allow null
-----------------------------------
Id int false
ParentId int true
TypeId int false
-----------------------------------
Field name Type Allow null
-----------------------------------
Id int false
ParentId int true
TypeId int false
Now, assume we want to find all items of TypeId 5, regardless of their parent items; indeed, regardless of whether they have a parent at all. The following request seems intuitive enough: GetItems(null, 5);. This will result in the C# expression item.ParentId == (null ?? item.ParentId), which is completely valid, but it will translate to the following SQL:
SELECT
*
FROM
Items
WHERE
ParentId = COALESCE(null, ParentId)
AND TypeId = COALESCE(5, TypeId)
*
FROM
Items
WHERE
ParentId = COALESCE(null, ParentId)
AND TypeId = COALESCE(5, TypeId)
For a record of ParentId 1 and TypeId 5, this will be just the way to do things, but if we consider the fact that there could exist an item with ParentId null and TypeId 5, the first COALESCE would return null, as both of its parameters would be of a null value. In SQL, this results in a null = null comparison, which will return false (hence the IS NULL syntax). Consequently, items with a ParentId of null will not be returned, even though the intention was to specify that the query should disregard of ParentId completely.
A workaround for the problem would be to rewrite a method accordingly:
Figure 2
public IEnumerable- GetItems(int? parentId, int? typeId)
{
myDataContext db = new myDataContext();
return from item in db.Items
where
((item.ParentId == null && parentId == null) || item.ParentId == (parentId ?? item.ParentId))
&& item.TypeId == (typeId ?? item.TypeId)
select item;
}
{
myDataContext db = new myDataContext();
return from item in db.Items
where
((item.ParentId == null && parentId == null) || item.ParentId == (parentId ?? item.ParentId))
&& item.TypeId == (typeId ?? item.TypeId)
select item;
}
Now, you don't have to look at figure 2 to realize that there's probably a better way to solve this problem. Expression trees would do the trick, for sure, but for our simple implementation, it turns out there's a less complex solution:
Figure 3
public IEnumerable- GetItems(int? parentId, int? typeId)
{
myDataContext db = new myDataContext();
var items = from item in db.Items select item;
if(parentId != null)
items = from item in items where item.ParentItemID == parentId select item;
if(typeId != null)
items = from item in items where item.ItemTypeID == typeId select item;
return items;
}
{
myDataContext db = new myDataContext();
var items = from item in db.Items select item;
if(parentId != null)
items = from item in items where item.ParentItemID == parentId select item;
if(typeId != null)
items = from item in items where item.ItemTypeID == typeId select item;
return items;
}
Beginning by selecting the entire set of items available, we then proceed to filter the results to match any of the criterias that may or may not be provided. At first glance, this would appear to begin by executing a plain SELECT * FROM Items query, returning all items in the table, even when we know that's not always requested, but as the result set - items - is never enumerated before the return statement, LINQ to SQL optimizes the above code into one query at runtime, depending on what values have been specified.
An SQL Profiler trace gives us the answers in plain text:
Figure 1
exec sp_executesql N'SELECT Id, TypeId, ParentId FROM Items WHERE (ParentId = (COALESCE(@p0,ParentId))) AND (TypeId = (COALESCE(@p1,TypeId)))',N'@p0 int,@p1 int',@p0=NULL,@p1=5
The query generated in Figure 1 returns 0 rows, which is not what we expect, given the data in the table.
Figure 2
exec sp_executesql N'SELECT Id, TypeId, ParentId FROM Items WHERE ((ParentId IS NULL) OR (ParentId = (COALESCE(@p0,ParentId)))) AND (TypeId = (COALESCE(@p1,TypeId)))',N'@p0 int,@p1 int',@p0=NULL,@p1=5
The query from Figure 2 gives us the result we want, but in a verbose and inconvenient query
Figure 3
exec sp_executesql N'SELECT Id, TypeId, ParentId FROM Items WHERE TypeId = @p0',N'@p0 int',@p0=5
From Figure 3, only one query is executed (although we appear to have begun by selecting everything in the table), and only the non-null parameter is passed.
Visual Studio 2008 fails to open certain projects
Visual Studio 2008 might fail when opening a project using an add-on package. The package might be a silverligt plug-in as well as the standard LINQ-to-SQL dialog.
When this happens VS gives you the following error message:
"Project <Name> could not be opened because the Microsoft Visual C# .NET compiler could not be created. QueryService for '{74946829-37A0-11D2-A273-00C04F8EF4FF}' failed."
...and the project will fail to load.
This is really weird, but the solution is to open "regedit" and navigate to:
"HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\Packages\"
Under this element you will find several "GUID"s (none with the GUID in the error message though). Open each of the GUID-elements and change the "SkipLoading" value to "0" (zero).
Restart VS 2008 and voilá - it is working again!
When this happens VS gives you the following error message:
"Project <Name> could not be opened because the Microsoft Visual C# .NET compiler could not be created. QueryService for '{74946829-37A0-11D2-A273-00C04F8EF4FF}' failed."
...and the project will fail to load.
This is really weird, but the solution is to open "regedit" and navigate to:
"HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\9.0\Packages\"
Under this element you will find several "GUID"s (none with the GUID in the error message though). Open each of the GUID-elements and change the "SkipLoading" value to "0" (zero).
Restart VS 2008 and voilá - it is working again!
Prenumerera på:
Kommentarer (Atom)