January 2009 - Posts
I didn't realize that error handling for HTTP requests got to the web service level. If you've deployed an app to a remote server that gets an error, you found that the error handling capabilities provided in the <customErrors> element in the config file catch the error and redirect to the error page (if this element is setup to do so; you can also catch errors in the Page_Error event).
What I found out was that errors in web service calls to the client side also get filtered out on a remote server. The error comes back as a 500 error with a generic message. ASP.NET AJAX is smart enough to handle failures and respond accordingly, but those errors get caught on the server and a generic gets sent to the client.
I found this out because I was displaying the error message and using exception throwing as a validation of sorts, displaying the message in the client. This didn't work however.
Suprisingly, IIS (at least 5 and I believe 6) doesn't support automatic redirect between HTTP and HTTPS. To handle this, you have to write an ISAPI add-on that will redirect to the new URL, or embed this logic in the application. To handle this, this can be done with JavaScript; I found this solution online:
if (window.location.protocol != 'https:')
window.location = 'https://' + location.host + location.pathname + location.search;
This simply changes the location if the protocol isn't HTTPS. Or, you can write .NET code that inspects the https:// using the Request.Uri.AbsoluteUri property, and if it isn't HTTPS, do this:
Response.Redirect("https://" + Request.Uri.AbsoluteUri.Replace("http://", ""));
This redirects to the HTTPS site.
This is one common variant to the strategy/state pattern that I commonly use. It varies in that I use a second object to actually figure out which stategy/state pattern object should be used in a given situation. For instance, suppose we had the following strategy pattern base class.
public abstract class TaxCalculator
{
public abstract decimal CalculateTaxAmount(Product product);
public abstract bool IsCorrectProduct(Product product);
public abstract decimal IsExemptFromTax(Product product);
}
So this is the base class. The key is the IsCorrectState method. This method determines which strategy pattern should be used; normally, in the state/strategy pattern examples, you see the corred State/Strategy object simply being instantiated. My approach works a little different. Before we get to that, let's look at an example:
public class OneHundredPercentJuiceCalculator : TaxCalculator
{
public override decimal CalculateTaxAmount(Product product)
{
return 0;
}
public override bool IsCorrectProduct(Product product)
{
return (product.Sku == 150483 || product.Sku == 434523);
}
public override decimal IsExemptFromTax(Product product)
{
return true;
}
}
Notice the IsCorrectProduct definition; it's the one that identifies which products qualify for evaluation. In this implementation, another object uses the collection of tax calculators to calculate taxes. Check out the TaxManager clas below.
public class TaxManager
{
private List<TaxCalculator> _calculators = new List<TaxCalculator>();
private TaxManager() { }
public static TaxManager GetInstance()
{
TaxManager mgr = new TaxManager();
mgr._calculators.Add(new OneHundredPercentJuiceCalculator());
mgr._calculators.Add(new CandyCalculator());
mgr._calculators.Add(new MilkCalculator());
mgr._calculators.Add(new CerealCalculator());
return mgr;
}
public bool IsExempt(Product product)
{
var calculator = _calculators.First(i => i.IsCorrectProduct(product));
return calculator.IsExemptFromTax(product);
}
public decimal CalculateTaxAmount(Product product)
{
var calculator = _calculators.First(i => i.IsCorrectProduct(product));
return calculator.CalculateTax(product);
}
}
The tax manager instantiates a list of all the TaxCalculator objects. In this example, the list of calculators is sealed, but this example could be expanded to allow other calculators to be registered. Whatever calculator is appropriate for the product is retrieved via the IsCorrectProduct method. This method evaluates every calculator to find the correct calculator for a given product. The calculator is returned, and its other method called; you can see this approach is like the Provider pattern in this example; though the TaxManager class is not static, it could be adapted to be.
In my opinion, this approach makes it easy to spread logic across multiple objects, while minimizing the amount of work that each method does. This could be achieved by adding additional helper methods to the base class, so each derived class has less to do. Additionally, there could be intermediate abstract classes that sit between the TaxCalculator class and the final derived classes that help make working with this pattern easier too. It all depends on the needs of the application.
For instance, suppose that alot of products return a six percent tax value and are not exempt. Another helper class could be defined as:
public abstract class SixPercentTaxCalculator : TaxCalculator
{
public override decimal CalculateTaxAmount(Product product)
{
return 1.06;
}
public override bool IsExemptFromTax(Product product)
{
return false;
}
}
Now, as long as classes inherit from this, those classes only have to inherit the IsCorrectCalculator method to figure out which calculator is correct.
I got this error when creating a new detached object. The issue was that a related object wasn't detached from the ObjectContext, but the detached object referenced an attached one. By detaching the related object when I assigned to the new object, this issue was resolved.
A great thread on this here: http://social.msdn.microsoft.com/forums/en-US/adodotnetentityframework/thread/5ee5db93-f8f3-44ef-8615-5002949bea71/
You may have noticed that I tend to shift subjects quite a bit. I talked about Agile a while ago, and have moved away from talking about it. I needed to grow and learn about the processes, which I have done a little. I'll always be a student in this subject, never fully grasping all that it has to offer. Even so, I love the whole Agile movement. What attracts me most is that this methodology embraces ideas like putting people first, development in smaller iterations, cycles, and chunks instead of developing sofware in a waterfall approach (which leads to problems in its own).
One of the emphasis of TDD is development in small chunks, and create automated unit tests first. Automated unit tests handle several development tasks:
- It forces you to see how your components are consumed by the client early on; the emphasis tends to be design the architecture on paper and up front. When this is the emphasis, the design sees problems down the road because the consumer requires different input or business rules than what was thought of during the requirements gathering.
- It serves as a unit test, and will never lose that status; it continually tests the code even after the code is released, maintained, and enhanced in future releases.
While this is all good and handy, refactoring poses some challenges. TDD doesn't iron out all the kinks at the beginning like it should, at least for the average Agile developer. While people like Kent Beck or Martin Fowler may never run into this issue, I run into it in my code. This is because even though I'm developing tests, there are some minor unforseen challenges that come down the road.
In a sense, this is what TDD and Agile is all about: developing in small manageable chunks and only focusing on the current task, not looking ahead. So when a future piece of the application comes into play that requires changes to older code, refactoring needs applied. But refactoring doesn't get applied to only the targeted class; rather, it targets any and all unit tests that have been coded for it. Depending on the size of the code, this could be a lot of tests to change. To find out, make the change, and compile the project in Visual Studio, Eclipse, MonoDevelop, or whatever software product you use. I know most TDD'ers consider this not a proper TDD approach (to rely on the compiler), but the compiler easily points out where changes have to be applied in unit and integration tests (integration tests are also a factor too in all of this).
I'm not against TDD or unit/integration tests; I love them, but when you design these tests, think from a object-oriented perspective in these tests as well and plan ahead, so that you can try to reduce the amount of changes you need to make when you refactor code. Your code not only needs a good design, but your unit/integration tests need a good design too.
If you try to use a CLR stored procedure as a stored procedure in a Reporting Services report, you may run into an issue where an error pops up, stating that the proc could not be found. This is an issue because the database provider can't see the CLR proc (more on this here: http://social.msdn.microsoft.com/forums/en-US/sqlreportingservices/thread/7f3eda53-efab-482c-84f0-9d0ff47c1f95/). In order to execute the CLR proc in a SSRS report, you'd have to set the command type as Text, and do:
exec myClrProc 'Params'
The issue with this is that the fields do not automatically get mapped this way, and it didn't work for me. SSRS automatically maps the field in the result set to fields that can be bound to in the report. The solution to this issue was to use the wrapper approach: the thread above worked well for me, which is to include a wrapper that calls the CLR stored procedure. Having the wrapper proc as:
create procedure myClrProcWrapper @Params
as
exec myClrProc @Params
Worked well and was a workaround to this issue; I can setup the myClrProcWrapper as a stored procedure and it can be called, and have the fields mapped over correctly.
A report I recently created required the use of a recurring number in a subreport in reporting services. Didn't know offhand how to do that, but figured it was easy to do. Along came RowNumber: http://msdn.microsoft.com/en-us/library/ms159225.aspx. This method takes a scope value which is a relative value to determine whether to continue incrementing numbers for the current scope, or to start back at the initial value.
In a subreport, providing RowNumber(Nothing) creates numbers starting at 1 up to X number of rows and starts over every time the subreport was created, the right action for what I was looking to do.
Because the .NET framework controls didn't plan in advance to be able to incorporate ASP.NET AJAX features into the framework, there can be certain things that make working with .NET controls harder. Take, for instance, the checkbox control. While this control is simple, to show or hide the checkbox is not as easy as simply accessing the element by it's ID and setting the style.display property to none.
A checkbox renders, with text, as:
<input type="checkbox" ../>
<label for="checkID">text</label>
So if you try to do this to hide the checkbox:
var check = $get("<%= checkID.ClientID %>");
check.style.display = "none";
The label element will still be visible. Using a separate <asp:Label> element and using $get() to return the reference to the label works as a way to get the checkbox label and show/hide it as well. Alternatively, the checkbox is wrapped with a <span> tag as such:
<span>
<input ..>
<label ..>
</span>
So if you want to show/hide a checkbox and the associated text, you can also do:
var check = $get("<%= checkID.ClientID %>");
check.parentNode.style.display = "none";
The parentNode method returns the reference to the parent node (the parent span tag, as the check object is referencing the <input> element). And thus, both the label/input tag are shown/hidden.