tag:blogger.com,1999:blog-3189598286364183282024-03-13T01:05:04.720+00:00Dominic Zukiewicz's Technical BlogAnonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-318959828636418328.post-79393937186816524882013-12-23T13:01:00.000+00:002015-01-09T19:40:55.128+00:00Configuring IoC Services per area in MVC In the <a href="http://dommyzee.blogspot.co.uk/2013/12/shared-user-interfaces-but-still.html">last blog post</a>, I described a solution that was broken down into different areas per location. The MVC project has this structure: <br />
<ul>
<li>Areas <ul>
<li>UK </li>
<li>US </li>
<li>HK </li>
</ul>
</li>
<li>Controllers </li>
<li>Views </li>
</ul>
Each area had shared UI implementations for the most part, but required specialisation on the business logic side. <br />
<h5>
Problem</h5>
Specialising the services isn’t too much of a problem. You have an interface for the basic functions, and then specialise them within. What made our implementation work difficult is that there were specific repositories for each area! This was because each area interacted with a database of differing schema AND differing platform.<br />
<h5>
Design</h5>
The design of the services is fairly straightforward. You create the interface and then specialise each implementation like this:<br />
<pre class="c-sharp" name="code">public interface IOrderService
{
OrderSummaryViewModel GetOrderSummary(string orderNumber);
OrderViewModel GetOrder(string orderNumber);
}
// US specific implementation
public class USOrderService : IOrderService
{
protected readonly IOrderRepository orderRep;
public USOrderService(IOrderRepository orderRep)
{
this.orderRep = orderRep;
}
public OrderSummaryViewModel GetOrderSummary(string orderNumber)
{
var order = orderRep.FirstOrDefault(o=>o.OrderReference == orderNumber);
if(order==null)
return OrderSummaryViewModel.NoOrderFound;
var model = new OrderSummaryViewModel
{
OrderNumber = order.OrderReference,
CustomerName = order.FirstName + " " + order.LastName,
OrderDate = order.CreatedDate,
OrderTotal = order.Lines.Sum(x=>x.Quantity * x.UnitPrice),
TaxTotal = order.Lines.Sum(x=>x.Quantity * x.UnitTaxPrice)
};
return model;
}
}</pre>
<br />
All very easy code. So lets say we have one service per area, resulting in:<br />
<ul>
<li>HKOrderService - using the <code><strong>Sql</strong>Repository</code> repository</li>
<li>USOrderService - using the <code><strong>Oracle</strong>Repository</code> repository</li>
<li>UKOrderService - using the <code><strong>Sybase</strong>Repository</code> repository</li>
</ul>
<br />
Therefore, to summarise we have these chains of dependencies:<br />
<br />
<table border="1"><thead>
<tr> <th valign="top">Area</th> <th valign="top">Controller (assuming Area namespace)</th> <th valign="top">Service</th> <th valign="top">Repository</th> </tr>
</thead><tbody>
<tr> <td valign="top">UK</td> <td valign="top">OrderSummaryController</td> <td valign="top">UKOrderService</td> <td valign="top">SybaseRepository</td> </tr>
<tr> <td valign="top">US</td> <td valign="top">OrderSummaryController</td> <td valign="top">USOrderService</td> <td valign="top">OracleRepository</td> </tr>
<tr> <td valign="top">HK</td> <td valign="top">OrderSummaryController</td> <td valign="top">HKOrderService</td> <td valign="top">SqlRepository</td> </tr>
</tbody></table>
<h4>
Solution</h4>
We were using <a href="http://autofac.org/" target="_blank">AutoFac</a> as our DI tool. Since MVC has DI support out of the box, this made it easier to start with. But breaking down dependencies by area was a little more tricky. <br />
<br />
AutoFac works by inheriting from a Module class, and then connecting the dependencies together within the module. If you’ve used <a href="http://docs.structuremap.net/" target="_blank">StructureMap</a> before, this is exactly the same as the <a href="http://docs.structuremap.net/RegistryDSL.htm" target="_blank">Registry</a> class.<br />
<br />
Here is an example of how it is implemented<br />
<br />
<pre class="c-sharp" name="code">public class ServiceInitializationModule : Module
{
private static readonly HKArea = "HK";
private static readonly USArea = "US";
private static readonly UKArea = "UK";
private static readonly SqlConfigKey = "SQL";
private static readonly OracleConfigKey = "ORA";
private static readonly SybaseConfigKey = "SYB";
public override Load(ContainerBuilder builder)
{
InitializeRepositories(builder);
InitializeFormatters(builder);
InitializeServices(builder);
}
// This registers a concrete implementation with an interface and assigns it a name for later retrieval.
private void InitializeRepositories(ContainerBuilder builder)
{
builder.Register( r => new SqlRepository (ConfigurationManager.ConnectionStrings[SqlConfigKey].ConnectionString))
.Named<IOrderRepository>(SqlDb)
.InstancePerHttpRequest();
builder.Register( r => new OracleRepository (ConfigurationManager.ConnectionStrings[OracleConfigKey].ConnectionString))
.Named<IOrderRepository>(OracleDb)
.InstancePerHttpRequest();
builder.Register( r => new SybaseRepository (ConfigurationManager.ConnectionStrings[SybaseConfigKey].ConnectionString))
.Named<IOrderRepository>(SybaseDb)
.InstancePerHttpRequest();
}
private void InitializeFormatters(ContainerBuilder builder)
{
builder.Register( r => new UKCurrencyFormatter() )
.Named<ICurrencyFormatter>()
.Singleton();
builder.Register( r => new USCurrencyFormatter() )
.Named<ICurrencyFormatter>(USAREA)
.Singleton();
builder.Register( r => new HKCurrencyFormatter() )
.Named<ICurrencyFormatter>(HKAREA)
.Singleton();
}
private void InitializeServices(ContainerBuilder builder)
{
builder.Register( r => new UKOrderService(
r.ResolveNamed<IOrderRepository>(SybaseDb))
.Named<IOrderService>(UKAREA)
.InstancePerHttpRequest();
builder.Register( r => new USOrderService(
r.ResolveNamed<IOrderRepository>(OracleDb))
.Named<IOrderService>(USAREA)
.InstancePerHttpRequest();
builder.Register( r => new HKOrderService(
r.ResolveNamed<IOrderRepository>(SqlDb))
.Named<IOrderService>(HKAREA)
.InstancePerHttpRequest();
}
}</pre>
<br />
This is only half the story. The DI is set up, but the controllers were taking interfaces in as parameters. Here they are again: <br />
<br />
<pre class="c-sharp" name="code">// Base Controller
public abstract class OrderSummaryBaseController : Controller
{
protected readonly IOrderService orderService;
protected readonly ICurrencyFormatter formatter;
protected OrderSummaryBaseController (IOrderService orderService, ICurrencyFormatter formatter)
{
this.orderService = orderService;
this.formatter = formatter;
}
}
// UK/Controller
public class OrderSummaryController : OrderSummaryBaseController
{
public OrderSummaryController ()
: base(new UKOrderService(), new UKCurrencyFormatter()) {}
public OrderSummaryController (IOrderService service, ICurrencyFormatter formatter)
: base(service, formatter) {}
}</pre>
<br />
So what is the problem? The problem is that there are multiple controllers called OrderSummaryController. They all have the same constructor, which looks identical and does conflict with the base class.<br />
<h5>
Quick-recap</h5>
<blockquote>
I'm throwing a lot of code at you at the moment. It is an important lesson to learn about how this solution is working in the bigger scheme of things. We want to use a controller and its base to share functionality. We also want to make sure the signatures match, as it will making unit testing much easier. My solution is attempting to keep the constructors the same signature, so that a) unit testing can be easier and b) so that when a new area is created, just the constructors need copying into the new file. </blockquote>
<br />
Ahh - you're back! Ok, so what are we trying to do? We want Autofac to differentiate between a class and its base. You'll find Autofac throws all sorts of resolution errors in this scenario. Luckily, if you don't mind taking the plunge and allowing a litle AutoFac code into your <strong>concrete</strong> controllers, all is not lost! <br />
<br />
<pre class="c-sharp" name="code">// UK/Controller
public class OrderSummaryController : OrderSummaryBaseController
{
<strike>public OrderSummaryController ()
: base(new UKOrderService(), new UKCurrencyFormatter()) {}</strike>
public OrderSummaryController (IOrderService service, ICurrencyFormatter formatter)
: base(service, formatter) {}
public OrderSummaryController (IComponentContext autoFacContext)
: base(
autoFactContext.ResolveNamed<IOrderService>(Areas.UK), // <- Resolves the UKOrderService
autoFacContext.ResolveNamed<ICurrencyFormatter>(Areas.UK));// <- Resolves the UKCurrencyFormatter
{
}
}</pre>
<br />
This constructor overload gives AutoFac an easy way in. The beauty of it is that the application is still unit testable via the <code>IOrderService</code> and <code>ICurrencyFormatter</code>, but the <code>IComponentContext</code> is giving you an easier (i.e. time-saving) way in. Now, time for the hooking-up within MVC. We need to register that <code>Module</code>, so that MVC resolves items correctly. The easiest (and most common way) is to inherit from the <code>DefaultControllerFactory</code> - the MVC built-in resolver - and register the <code>ServiceInitializationModule</code>. We then re-point MVC at this resolver instead of its default one. <br />
<br />
<pre class="c-sharp" name="code">public class AutofacControllerFactory : DefaultControllerFactory
{
private readonly ContainerBuilder builder;
public AutofacControllerFactory()
{
this.builder = new ContainerBuilder();
this.AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
var controller = DependencyResolver.Current.GetService(controllerType) as IController;
return controller;
}
public virtual void AddBindings()
{
this.builder.RegisterModule(new ServiceInitializationModule());
DependencyResolver.SetResolver(new AutofacDependencyResolver(this.container)); //<-- Tell MVC to use the AutoFac resolver, instead of the default.
}
}</pre>
<br />
And now tell MVC to use this <code>AutofacControllerFactory</code> when creating controllers... <br />
<br />
<pre class="c-sharp" name="code">// Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// Use the MVC 4 file structure, as its cleaner.
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BinderConfig.RegisterModelBinders(ModelBinders.Binders);
// Resolve using my custom controller factory
ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory());
}</pre>
<br />
And we are done!<br />
<h5>
Summary</h5>
<br />
In this blog, I've described a scenario where an MVC application is separated into areas. Those areas all use different services, due to the business logic being different for them. In addition, the repositories themselves are also different.<br />
<br />
Therefore, you should have come away with the following points<br />
<br />
<ol>
<li>A base controller can have multiple implementations in different areas</li>
<li>Areas can have different services being injected into the controllers</li>
<li>The services can even have repositories of differing <i>concrete </i>types injected as well.</li>
</ol>
<div>
This analysis took several weeks to get working. I wasn't able to find it possible with any other framework, but if you do find one that does, let me know!</div>
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-14046887623441590832013-12-23T11:06:00.001+00:002015-01-09T19:42:47.788+00:00Shared user interfaces, but still allowing for customisation per areaIn the <a href="http://dommyzee.blogspot.co.uk/2013/12/shared-user-interfaces-but-still.html">last blog post</a>, I described a solution that was broken down into different areas per location. The MVC project has this structure: <br />
<ul>
<li>Areas <ul>
<li>UK </li>
<li>US </li>
<li>HK </li>
</ul>
</li>
<li>Controllers </li>
<li>Views </li>
</ul>
Each area had shared UI implementations for the most part, but required specialisation on the business logic side. <br />
<h5>
Problem</h5>
Specialising the services isn’t too much of a problem. You have an interface for the basic functions, and then specialise them within. What made our implementation work difficult is that there were specific repositories for each area! This was because each area interacted with a database of differing schema AND differing platform.<br />
<h5>
Design</h5>
The design of the services is fairly straightforward. You create the interface and then specialise each implementation like this:<br />
<pre name="code" class="c-sharp">public interface IOrderService
{
OrderSummaryViewModel GetOrderSummary(string orderNumber);
OrderViewModel GetOrder(string orderNumber);
}
// US specific implementation
public class USOrderService : IOrderService
{
protected readonly IOrderRepository orderRep;
public USOrderService(IOrderRepository orderRep)
{
this.orderRep = orderRep;
}
public OrderSummaryViewModel GetOrderSummary(string orderNumber)
{
var order = orderRep.FirstOrDefault(o=>o.OrderReference == orderNumber);
if(order==null)
return OrderSummaryViewModel.NoOrderFound;
var model = new OrderSummaryViewModel
{
OrderNumber = order.OrderReference,
CustomerName = order.FirstName + " " + order.LastName,
OrderDate = order.CreatedDate,
OrderTotal = order.Lines.Sum(x=>x.Quantity * x.UnitPrice),
TaxTotal = order.Lines.Sum(x=>x.Quantity * x.UnitTaxPrice)
};
return model;
}
}</pre>
<br />
All very easy code. So lets say we have one service per area, resulting in:<br />
<ul>
<li>HKOrderService - using the <code><strong>Sql</strong>Repository</code> repository</li>
<li>USOrderService - using the <code><strong>Oracle</strong>Repository</code> repository</li>
<li>UKOrderService - using the <code><strong>Sybase</strong>Repository</code> repository</li>
</ul>
<br />
Therefore, to summarise we have these chains of dependencies:<br />
<br />
<table border="1"><thead>
<tr> <th valign="top">Area</th> <th valign="top">Controller (assuming Area namespace)</th> <th valign="top">Service</th> <th valign="top">Repository</th> </tr>
</thead><tbody>
<tr> <td valign="top">UK</td> <td valign="top">OrderSummaryController</td> <td valign="top">UKOrderService</td> <td valign="top">SybaseRepository</td> </tr>
<tr> <td valign="top">US</td> <td valign="top">OrderSummaryController</td> <td valign="top">USOrderService</td> <td valign="top">OracleRepository</td> </tr>
<tr> <td valign="top">HK</td> <td valign="top">OrderSummaryController</td> <td valign="top">HKOrderService</td> <td valign="top">SqlRepository</td> </tr>
</tbody></table>
<h4>
Solution</h4>
We were using <a href="http://autofac.org/" target="_blank">AutoFac</a> as our DI tool. Since MVC has DI support out of the box, this made it easier to start with. But breaking down dependencies by area was a little more tricky. <br />
<br />
AutoFac works by inheriting from a Module class, and then connecting the dependencies together within the module. If you’ve used <a href="http://docs.structuremap.net/" target="_blank">StructureMap</a> before, this is exactly the same as the <a href="http://docs.structuremap.net/RegistryDSL.htm" target="_blank">Registry</a> class.<br />
<br />
Here is an example of how it is implemented<br />
<br />
<pre name="code" class="c-sharp">public class ServiceInitializationModule : Module
{
private static readonly HKArea = "HK";
private static readonly USArea = "US";
private static readonly UKArea = "UK";
private static readonly SqlConfigKey = "SQL";
private static readonly OracleConfigKey = "ORA";
private static readonly SybaseConfigKey = "SYB";
public override Load(ContainerBuilder builder)
{
InitializeRepositories(builder);
InitializeFormatters(builder);
InitializeServices(builder);
}
// This registers a concrete implementation with an interface and assigns it a name for later retrieval.
private void InitializeRepositories(ContainerBuilder builder)
{
builder.Register( r => new SqlRepository (ConfigurationManager.ConnectionStrings[SqlConfigKey].ConnectionString))
.Named<IOrderRepository>(SqlDb)
.InstancePerHttpRequest();
builder.Register( r => new OracleRepository (ConfigurationManager.ConnectionStrings[OracleConfigKey].ConnectionString))
.Named<IOrderRepository>(OracleDb)
.InstancePerHttpRequest();
builder.Register( r => new SybaseRepository (ConfigurationManager.ConnectionStrings[SybaseConfigKey].ConnectionString))
.Named<IOrderRepository>(SybaseDb)
.InstancePerHttpRequest();
}
private void InitializeFormatters(ContainerBuilder builder)
{
builder.Register( r => new UKCurrencyFormatter() )
.Named<ICurrencyFormatter>()
.Singleton();
builder.Register( r => new USCurrencyFormatter() )
.Named<ICurrencyFormatter>(USAREA)
.Singleton();
builder.Register( r => new HKCurrencyFormatter() )
.Named<ICurrencyFormatter>(HKAREA)
.Singleton();
}
private void InitializeServices(ContainerBuilder builder)
{
builder.Register( r => new UKOrderService(
r.ResolveNamed<IOrderRepository>(SybaseDb))
.Named<IOrderService>(UKAREA)
.InstancePerHttpRequest();
builder.Register( r => new USOrderService(
r.ResolveNamed<IOrderRepository>(OracleDb))
.Named<IOrderService>(USAREA)
.InstancePerHttpRequest();
builder.Register( r => new HKOrderService(
r.ResolveNamed<IOrderRepository>(SqlDb))
.Named<IOrderService>(HKAREA)
.InstancePerHttpRequest();
}
}</pre>
<br />
This is only half the story. The DI is set up, but the controllers were taking interfaces in as parameters. Here they are again: <br />
<br />
<pre name="code" class="c-sharp">// Base Controller
public abstract class OrderSummaryBaseController : Controller
{
protected readonly IOrderService orderService;
protected readonly ICurrencyFormatter formatter;
protected OrderSummaryBaseController (IOrderService orderService, ICurrencyFormatter formatter)
{
this.orderService = orderService;
this.formatter = formatter;
}
}
// UK/Controller
public class OrderSummaryController : OrderSummaryBaseController
{
public OrderSummaryController ()
: base(new UKOrderService(), new UKCurrencyFormatter()) {}
public OrderSummaryController (IOrderService service, ICurrencyFormatter formatter)
: base(service, formatter) {}
}</pre>
<br />
So what is the problem? The problem is that there are multiple controllers called OrderSummaryController. They all have the same constructor, which looks identical and does conflict with the base class.<br />
<h5>
Quick-recap</h5>
<blockquote>
I'm throwing a lot of code at you at the moment. It is an important lesson to learn about how this solution is working in the bigger scheme of things. We want to use a controller and its base to share functionality. We also want to make sure the signatures match, as it will making unit testing much easier. My solution is attempting to keep the constructors the same signature, so that a) unit testing can be easier and b) so that when a new area is created, just the constructors need copying into the new file. </blockquote>
<br />
Ahh - you're back! Ok, so what are we trying to do? We want Autofac to differentiate between a class and its base. You'll find Autofac throws all sorts of resolution errors in this scenario. Luckily, if you don't mind taking the plunge and allowing a litle AutoFac code into your <strong>concrete</strong> controllers, all is not lost! <br />
<br />
<pre name="code" class="c-sharp">// UK/Controller
public class OrderSummaryController : OrderSummaryBaseController
{
<strike>public OrderSummaryController ()
: base(new UKOrderService(), new UKCurrencyFormatter()) {}</strike>
public OrderSummaryController (IOrderService service, ICurrencyFormatter formatter)
: base(service, formatter) {}
public OrderSummaryController (IComponentContext autoFacContext)
: base(
autoFactContext.ResolveNamed<IOrderService>(Areas.UK), // <- Resolves the UKOrderService
autoFacContext.ResolveNamed<ICurrencyFormatter>(Areas.UK));// <- Resolves the UKCurrencyFormatter
{
}
}</pre>
<br />
This constructor overload gives AutoFac an easy way in. The beauty of it is that the application is still unit testable via the <code>IOrderService</code> and <code>ICurrencyFormatter</code>, but the <code>IComponentContext</code> is giving you an easier (i.e. time-saving) way in. Now, time for the hooking-up within MVC. We need to register that <code>Module</code>, so that MVC resolves items correctly. The easiest (and most common way) is to inherit from the <code>DefaultControllerFactory</code> - the MVC built-in resolver - and register the <code>ServiceInitializationModule</code>. We then re-point MVC at this resolver instead of its default one. <br />
<br />
<pre name="code" class="c-sharp">public class AutofacControllerFactory : DefaultControllerFactory
{
private readonly ContainerBuilder builder;
public AutofacControllerFactory()
{
this.builder = new ContainerBuilder();
this.AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
var controller = DependencyResolver.Current.GetService(controllerType) as IController;
return controller;
}
public virtual void AddBindings()
{
this.builder.RegisterModule(new ServiceInitializationModule());
DependencyResolver.SetResolver(new AutofacDependencyResolver(this.container)); //<-- Tell MVC to use the AutoFac resolver, instead of the default.
}
}</pre>
<br />
And now tell MVC to use this <code>AutofacControllerFactory</code> when creating controllers... <br />
<br />
<pre name="code" class="c-sharp">// Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// Use the MVC 4 file structure, as its cleaner.
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BinderConfig.RegisterModelBinders(ModelBinders.Binders);
// Resolve using my custom controller factory
ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory());
}</pre>
<br />
And we are done!<br />
<h5>
Summary</h5>
<br />This is part 1 of a series of blogs, where I aim to give an answer to a question I posted on <a href="http://stackoverflow.com/questions/17476353/multi-tenant-application-with-mvc-3-and-di" target="_blank">StackOverflow</a> a while ago. Although the answer was useful, the solution was already implemented and thought it would be best to describe what the problem in more detail.<br />
<h4>
Problem</h4>
Our team were tasked with creating a consistent looking website, which would interact across several different locations. The locations would all be owned by a parent company, who were creating the site. At the project outset, an estimated 70-90% of the <strong>UI </strong>would look the same. There were caveats to be aware of when developing the site.<br />
<ol>
<li>Each location used a different order number format </li>
<li>Each location has a custom currency format for the screen. For example; <ul>
<li>United Kingdom (2 decimal places) = 1.00 <strong>GBP</strong> </li>
<li>Hong Kong (4 decimal places) = 1.0000 <strong>HKD</strong> </li>
<li>United States (3 decimal places) = 1.000 <strong>USD</strong> </li>
</ul>
</li>
<li>Each location had a different database schema – as these companies were buyouts. </li>
<li>Each location <em>may</em> contain a different database platform. </li>
<li>Each location may (or may not) require customised business rules. A base set of rules would be applicable and customised as such. </li>
</ol>
<h4>
Design</h4>
The application was divided into 3 parallel sections / areas. The MVC structure of the application looked like this:<br />
<ul>
<li>Areas <ul>
<li>UK <ul>
<li>Controllers </li>
<li>Views </li>
</ul>
</li>
<li>US </li>
<li>HK </li>
</ul>
</li>
<li>Controllers </li>
<li>Views </li>
</ul>
We also had some idea that most of the functionality would be the same, expect for specific UI tweaks. Luckily, the idea of shared functionality became apparent very early on in the project, so we had a starting point to go from.<br />
<h4>
Solution</h4>We decided to have a base controller to contain a usual-case scenario for a particular process in the shared <code>~/Controllers</code> directory. Each area would then inherit from this base controller, so that functionality was always available for all areas by default. The only additional work required was when the area needed to specialise the behaviour.
<h5>Base Controller Implementation</h5>
Here is an example of this approach:<br />
<pre name="code" class="c-sharp">// ~/Controllers
public abstract class OrderSummaryBaseController : Controller
{
protected readonly IOrderService orderService;
protected readonly ICurrencyFormatter currencyFormatter;
protected OrderSummaryBaseController(IOrderService orderService, ICurrencyFormatter currencyFormatter)
{
this.orderService = orderService;
this.currencyFormatter = currencyFormatter
}
public virtual ViewResult Index(string orderNumber)
{
var viewModel = this.orderService.GetOrderSummary(orderNumber);
viewModel.Formatter = currencyFormatter;
return this.View(viewModel);
}
}
// ~/Areas/US/Controllers
public class OrderSummaryController : OrderSummaryBaseController
{
// Poor mans IoC - to demonstrate the intent
public OrderSummaryController()
: base( new <strong>US</strong>OrderService(), new <em>US</em>CurrencyFormatter() ) {}
}</pre>
This was a good starting point for us, because we always had out-of-the-box functionality available to us. We only implemented additional functionality when required.
<h5>Overriding a view</h5>
We also had the additional benefit of having some inside knowledge of the ViewModel coming back, because we knew what service we were calling. This came in handy when the <code>View</code> had to be re-implemented. For example:<br />
<br />
<pre name="code" class="c-sharp">// ~/Areas/US/Controllers
public override ViewResult Index(string orderNumber)
{
var viewModel = this.orderService.GetOrderSummary(orderNumber);
<b>var usViewModel = viewModel as USViewModel;</b>
if(usViewModel!=null)
{
usViewModel.HideTaxCalculations = true;
}
return this.View(viewModel);
}</pre>
I am abusing the inheritance structure here. It is almost as good as putting <code>new</code> in the method declaration. To respect the base classes implementation, another approach is:
<pre name="code" class="c-sharp">// ~/Areas/US/Controllers
public override ViewResult Index(string orderNumber)
{
var viewResult = base.Index(orderNumber);
<b>var viewModel = viewResult.ViewData.Model;</b>
var usViewModel = viewModel as USViewModel;
if(usViewModel!=null)
{
usViewModel.HideTaxCalculations = true;
}
return this.View(viewModel);
}</pre>
<h4>Quick re-cap - what have we actually achieved here?</h4>
What we have achieved is a shared single controller, that allows customisation when required. By default, all controllers will use the same view. If you wanted to add a significantly different view, you can add it to the area, so that there is a clean separation of concerns. So lets say the UK has a customised branding of the order summary screen - radically different from the default, you can add it to the specific area:<br />
<ul>
<li>Areas</li>
<ul>
<li>UK <ul>
<li>Controllers <ul>
<li>OrderSummaryController</li>
</ul>
</li>
<li>Views <br /> <ul>
<li>OrderSummary <br /> <ul>
<li>Index.cshtml </li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>US / HK</li>
<ul>
<li>Controllers</li>
<ul>
<li>OrderSummaryController</li>
</ul>
</ul>
</ul>
<li>Controllers </li>
<ul>
<li>OrderSummaryBaseController </li>
</ul>
<li>Views <br /> <ul>
<li>OrderSummary <br /> <ul>
<li>Index.cshtml </li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Summary</h4>
In this blog post, I demonstrated the use of a shared controllers, whilst allowing customisation between areas when required. This allows a new area to be built *almost* out of the box immediately.<br />
<br />
There is a problem with this example; every controller is using a poor mans Dependency Injection. That means when a new area is brought in, every controller needs to be re-implemented.<br />
<br />
So in the next blog, I will show you how we tackled this problem, so that new areas need only a little configuration to get up and running.
In this blog, I've described a scenario where an MVC application is separated into areas. Those areas all use different services, due to the business logic being different for them. In addition, the repositories themselves are also different.<br />
<br />
Therefore, you should have come away with the following points<br />
<br />
<ol>
<li>A base controller can have multiple implementations in different areas</li>
<li>Areas can have different services being injected into the controllers</li>
<li>The services can even have repositories of differing <i>concrete </i>types injected as well.</li>
</ol>
<div>
This analysis took several weeks to get working. I wasn't able to find it possible with any other framework, but if you do find one that does, let me know!</div>
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-80756325663600723182012-04-02T22:19:00.001+01:002013-05-21T08:29:58.200+01:00Encrypting your settings in your App.config filesI’m currently brushing up on my WCF after my exposure to WSE 3.0 a few years ago. In anticipation of upcoming client work and lack of a <a href="http://www.microsoft.com/learning/en/us/exam.aspx?id=70-513">TS: WCF Application with the .NET Framework 4</a> book based material (note it is only <a href="http://www.microsoft.com/learning/en/us/exam.aspx?id=70-513#tab3">course-based</a>), I opted for a good solid book that covered the subject matter in a thorough way.<br />
<br />
I opted for <a href="http://www.amazon.co.uk/Windows-Communication-Foundation-Step-Microsoft/dp/0735645566/ref=sr_1_1?ie=UTF8&qid=1333401816&sr=8-1">WCF 4 Step by Step by John Sharp</a>, as I had purchased the<a href="http://www.amazon.co.uk/Microsoft-Windows-Communication-Foundation-Developer/dp/0735623368/ref=ntt_at_ep_dpt_7"> previous WCF book</a> he published a few years ago. I did like his thorough style because I needed to learn it from scratch.<br />
<br />
In Chapter 4, “Protecting an Enterprise WCF Service”, he uses some examples where you enter your domain, username and password directly into the code(!). BUT – he does have a warning on every code sample:<br />
<blockquote class="tr_bq" style="border-radius: 10px; border: solid 1px gray; padding: 4px;">
<b>Warning:</b> This code is for illustrative purposes in this exercise only. In a production application, you should prompt the user for their name and password. You should <i>never</i> hard-code these details into an application.</blockquote>
Now, I do nearly all of my development on my work laptop. The thought of someone just searching my computer remotely for files with my well-known domain and username puts me off completely. So instead, I decided to apply encryption to it and looked for a way which did not require me to write another program.<br />
<h4>
Using existing tools to apply the encryption</h4>
In the TS: Web Applications with the .NET Framework 4, they discussed how to encrypt the <code><connectionStrings></code> section in your web.config. However, I want to leverage this to encrypt my <code><appSettings></code> section instead.<br />
<br />
First thing, start up a Visual Studio Command Prompt and CD to your location. We want to rename the app.config (prior to the build process) to web.config. For this example, we’ll assume my application in development is at <code>C:\Projects\EncryptConfig</code> directory.<br />
<pre class="brush:text">C:\> cd C:\Projects\EncryptConfig
C:\Projects\EncryptConfig> ren app.config web.config
</pre>
Next is to leverage the encryption utilities in the aspnet_regiis utility. All we provide is the section to encrypt and the file to apply the encryption to:<br />
<pre class="brush: text">aspnet_regiis –pef “appSettings” .
</pre>
The <code>–pef</code> indicates we want to encrypt a specific section and provide the filename. If you have CD’d to the directory, you can just use <code>–pe “appSettings”</code> and it will look for the web.config file.<br />
<br />
The next step is to rename the file back to an app.config:<br />
<pre class="brush:text">ren web.config app.config</pre>
You will notice that the app.config has encrypted this section like this:<br />
<pre class="brush: xml"><appSettings configProtectionProvider="DataProtectionConfigurationProvider">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAaUZOOb4EQkGNPyy5tzAjBgQAAAACAAAAAAADZgAAwAAAABAAAADQc+YHWZxsOuA55uoTOnvLAAAAAASAAACgAAAAEAAAAPYMaWCQj/hrK3T9DwGH2rxQAQAAyGBicUMztQUL+3cm7QJa5Nxf0NIlHv8WcT7rog67OaMFFc09qVZjmoloAaSsSZMLJC+Xof42NQ1H+x90kOASWvyWibqXkczP7bIy5/9whKb9T0eoHgpnqKu+WmiQQCf7pnM5XIY25TJ1uxzSu+pWZfabLkzfFZah6PaT/fLNCR7DLraewvX7LMmQk2+YLhEot+RDrXAtum7qpCweFFLCS8g8L9tTpz/XzKFjaXJqlJAGru8f9+PgEDOBCVxic8cvzjKizyxSQlS55ht0bJUD1NO6LGOQwtek7SKX2DjOCqQoWGf1uVXePtft73eN+JY7wcCjftu6IWQqUYdj2DMCFn6vZhaNYF5TkHtKv4kpZtNer+s50Yc8E2uUPq99ZZ8vZQMiGdQ8xopIWwx5F/WFUxpeQ5/hG4A4IKhY2njSC3m/efH4M28MWET34HTXVx1gFAAAAGC4o4MxMGI73etkgTMojENDadwS
</CipherValue>
</CipherData>
</EncryptedData>
</appSettings>
</pre>
The thing to note here is it is using the <code><a href="http://msdn.microsoft.com/en-us/library/system.configuration.dpapiprotectedconfigurationprovider.aspx">DataProtectionConfigurationProvider</a></code> accesses the Data Protection API which is a user-specific API. It is fine as long as you always log in with your user, on your domain. But if you tried to distribute this application, the section would never be able to be read by another computer.<br />
<br />
The <code><a href="http://msdn.microsoft.com/en-us/library/ff650304.aspx#paght000006_step2">RSAProtectedConfigurationProvider</a></code> allows you to encrypt specific to the user or the machine. It also allows you to export the key so that it can be moved to another machine. This would be useful over a web farm (this is an IIS tool after all), where the <code><machineKey></code> can be shared across computers.<br />
<br />
In any case, if you are looking to distribute this application and encrypt the contents of a configuration file, be sure you understand what encryption methods are available to you.Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com3tag:blogger.com,1999:blog-318959828636418328.post-54304650904262927692012-04-02T14:03:00.000+01:002012-04-02T14:17:07.639+01:00SyntaxHighlighter - a syntax highlighter for blog posts<p>I usually use Windows Live Writer to do my blogs. I also have some add-ins to support the syntax highlight, which embeds the CSS into the page.</p> <p>Today, I viewed the source on my own page, and here is an example of what the "Insert Code Snippet" generated:</p><pre class="brush: c-sharp">// Original formatting with no CSS<br>Console.WriteLine("Hello World!");<br>Console.WriteLine("Hello World!");<br>Console.WriteLine("Hello World!");</pre>Gets rendered to ....<br><br /><pre class="brush: xml"><br /><div id="codeSnippetWrapper"><br /> <br><br /> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt;<br /> background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%;<br /> padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr;<br /> border-top-style: none; color: black; border-right-style: none; font-size: 8pt;<br /> overflow: visible; padding-top: 0px" id="codeSnippet"><br /> <br /><br /> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt;<br /> background-color: white; margin: 0em; border-left-style: none; padding-left: 0px;<br /> width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace;<br /> direction: ltr; border-top-style: none; color: black; border-right-style: none;<br /> font-size: 8pt; overflow: visible; padding-top: 0px"><br /><br /> <span style="color: #606060" id="lnum1">1:</span><br /><br /> Console.WriteLine(<span style="color: #006080">"Hello World!"</span>);</pre><br /> <br /><br /> <!--CRLF--><br /> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt;<br /> background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px;<br /> width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace;<br /> direction: ltr; border-top-style: none; color: black; border-right-style: none;<br /> font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060"<br /> id="lnum2">2:</span><br /><br /> Console.WriteLine(<span style="color: #006080">"Hello World!"</span>);</pre><br /> <!--CRLF--><br /> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt;<br /> background-color: white; margin: 0em; border-left-style: none; padding-left: 0px;<br /> width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace;<br /> direction: ltr; border-top-style: none; color: black; border-right-style: none;<br /> font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060"<br /> id="lnum3">3:</span> <br/><br /> Console.WriteLine(<span style="color: #006080">"Hello World!"</span>);</pre><br /> <!--CRLF--><br /> </div><br /></div></pre>Okay, that is pretty horrific. Does the job, no doubt but when it comes to editing this in the application, it is a complete nightmare. It selects single rows, changes their width accidently. When you have a bit of luck actually selecting the outer div, the Code Snippet editor even warns you that it is going to attempt to read it. When viewing this on a mobile device, it looks even worse. Much worse trust me!<br><br>At the same time I was catching up with my Google Reader and was looking through posts I'd missed by Scott Hanselman. He was looking for a <a href="http://www.hanselman.com/blog/BestCodeSyntaxHighlighterForSnippetsInYourBlog.aspx">syntax highlighter for Windows Live Writer</a> a few years ago. He also went to the trouble of writing a Windows Live Writer plug-in for it. But luckily, things have been made much easier.<h2>How to add SyntaxHighlighter to your site</h2><ol><li>Download the Javascript and CSS libraries from the <a href="http://alexgorbatchev.com/SyntaxHighlighter/download/">SyntaxHighligter authors site</a>. (Alternatively reference them as described) <br /><li>Add a few lines of script, referencing the code types you wish to use, including the core libraries.<br /><blockquote><pre class="brush: xml"><script src="shCore.js" type="text/javascript"></script><br><script src="shAutoloader.js" type="text/javascript"></script> <br><script type="text/javascript">SyntaxHighlighter.autoloader( <br> 'js jscript javascript /js/shBrushJScript.js', <br> 'csharp c-sharp /js/shBrushCSharp.js',<br> 'xml /js/shBrushXml.js'<br>);<br><br><br>SyntaxHighlighter.all(); </pre></blockquote><cite> <a href="http://alexgorbatchev.com/SyntaxHighlighter/manual/api/autoloader.html">http://alexgorbatchev.com/SyntaxHighlighter/manual/api/autoloader.html</a></cite> <br></li></ol>In your HTML of your blog post, or site, all you do is add the nice and friendly <pre> tag that we all know and love, applied with a 'class' attribute with your programming language - simples!. <br><br>So here is a code sample <a href="http://dommyzee.blogspot.co.uk/2012/03/using-powershell-to-modify.html">(from a previous post)</a> and the newer way I will be blogging from now on:<br/><h3>Before</h3><div id="codeSnippetWrapper"><br /><div style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> # PowerShell script <span style="color: blue">to</span> modify the 'timeout' value <span style="color: blue">in</span> the specified web.config </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> # when no Sessions are <span style="color: blue">in</span> use. </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> # Constants used throughout application </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> $webConfig = <span style="color: #006080">"d:\web.config"</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> $newTimeout = <span style="color: #006080">"20"</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> $sessionCount = 0 </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> ## BEGIN </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> write-host Getting performance counters ... </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> $perfCounterString = <span style="color: #006080">"\asp.net applications(__total__)\sessions total"</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> $perfCounter = get-counter -counter $perfCounterString </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> $rawValue = $perfCounter .CounterSamples[0].CookedValue </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> write-host Session Count is $rawValue </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> <span style="color: blue">if</span>( $rawValue -gt $sessionCount) </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> { </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> write-host Session Count = $rawValue - exiting </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> <span style="color: blue">exit</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> } </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> write-host Stopping IIS </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> stop-service <span style="color: #006080">"IISAdmin"</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> # Open file and change value </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> $doc = new-object System.Xml.XmlDocument </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> $doc.Load($webConfig) </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span> $doc.SelectSingleNode(<span style="color: #006080">"//sessionState"</span>).timeout = $newTimeout </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> $doc.Save($webConfig) </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> write-host Starting IIS </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum34"> 34:</span> start-service <span style="color: #006080">"IISAdmin"</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum35"> 35:</span> </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum36"> 36:</span> write-host Done! </pre><pre style="text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum37"> 37:</span> ## END</pre></div></div><br/><h3>After</h3><br><pre class="brush: ps"># PowerShell script to modify the 'timeout' value in the specified web.config <br># when no Sessions are in use. <br><br># Constants used throughout application <br>$webConfig = "d:\web.config" <br>$newTimeout = "20" <br>$sessionCount = 0 <br><br>## BEGIN <br>write-host Getting performance counters ... <br>$perfCounterString = "\asp.net applications(__total__)\sessions total" <br>$perfCounter = get-counter -counter $perfCounterString <br>$rawValue = $perfCounter .CounterSamples[0].CookedValue <br><br>write-host Session Count is $rawValue <br><br>if( $rawValue -gt $sessionCount) <br>{ <br> write-host Session Count = $rawValue - exiting <br> exit <br>}<br><br>write-host Stopping IIS <br>stop-service "IISAdmin" <br><br># Open file and change value <br>$doc = new-object System.Xml.XmlDocument <br>$doc.Load($webConfig) <br>$doc.SelectSingleNode("//sessionState").timeout = $newTimeout <br>$doc.Save($webConfig) <br><br>write-host Starting IIS <br>start-service "IISAdmin" <br>write-host Done! <br>## END</pre><br /><p>Have a look at the source of this page to see how readable each section is.</p> Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com1tag:blogger.com,1999:blog-318959828636418328.post-26478571493984676482012-03-27T11:02:00.001+01:002012-04-01T21:24:54.483+01:00Using PowerShell to modify configuration files in IIS when the Session Count is 0(Apologies for re-posting this – I thought I was deleting a draft post and ended up deleting the actual post!)<br />
I was looking at Stack Overflow today and I saw <a href="http://stackoverflow.com/q/9734561/128444" target="_blank">a question </a>where a user wanted to change the Web.config when the number of Sessions reaches 0. He wasn’t aware of any way to find out the Session Count, or any automated way to do this. I thought I’d have a go anyway using a C# .NET Console Application anyway … but then I discovered PowerShell!<br /><br />To summarise PowerShell, think of it like a command prompt on steroids! Not only can you do the usual process starting, killing and file system navigation, but it provides a much more streamlined command system. You also have hundreds, if not thousands of commands at your disposal.<br />So let me talk you through how I would have done this in .NET and then the equivalent PowerShell implementation I used.<br />
<h2>
Goals of the application</h2>
<ol>
<li>Get the Session Count of IIS in total from a performance counter </li>
<li>If Count > 0, quit </li>
<li>Stop IIS </li>
<li>Change web.config </li>
<li>Start IIS</li>
</ol>
<h2>
Retrieving performance counters in .NET for the Session Count</h2>
I’ve recently passed my <a href="http://www.microsoft.com/learning/en/us/exam.aspx?id=70-516" target="_blank">TS: Data Applications in the .NET 4 Framework</a> exam, which covered how to create and retrieve performance counter data into your applications. So there’s step one – wait until the <strong>Active </strong>Session Count is 0. An example of retrieving this is:<br />
<br />
<pre class="brush: c-sharp">
var counter = new PerformanceCounter(
"ASP.NET Applications",
"Sessions Active",
"__Total__",
true);
var sessionCount = counter.RawValue;
if( sessionCount > 0 )
{
Console.WriteLine("Session Count is {0} - exiting", sessionCount );
return;
}
</pre>
<br />
These values match up to those in the Performance Monitor (perfmon.exe).<br />
<br />
In PowerShell, performance counters are easily retrieved as well. There is a specific command for retrieving them. PowerShell declares variables inline using a $ prefix, so here is how to retrieve the same counter in PowerShell. I saved these to a file called “ChangeIIS.ps1”:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> # Set up the string</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> $perfCounterString = <span style="color: #006080;">"\asp.net applications(__total__)\sessions active"</span></pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> # Retrieve the counter</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> $perfCounter = get-counter -counter $perfCounterString </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum6" style="color: #606060;"> 6:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum7" style="color: #606060;"> 7:</span> # Retrieve the raw value <span style="color: blue;">for</span> the first (and only) counter</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum8" style="color: #606060;"> 8:</span> $rawValue = $counter.CounterSamples[0].CookedValue </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum9" style="color: #606060;"> 9:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum10" style="color: #606060;"> 10:</span> <span style="color: blue;">if</span>( $rawValue -gt 0 )</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum11" style="color: #606060;"> 11:</span> {</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum12" style="color: #606060;"> 12:</span> write-host Session Count is $rawValue - exiting</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum13" style="color: #606060;"> 13:</span> <span style="color: blue;">exit</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum14" style="color: #606060;"> 14:</span> }</pre>
</div>
</div>
<br />
<h2>
Stopping & Starting IIS</h2>
This process is straightforward as well in both languages. First C#:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> var iisProcess = ServiceController.GetServices().First(s =><span style="color: green;"> s.ServiceName == "IISADMIN");</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> iisProcess.Stop()<span style="color: green;">;</span></pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> <span style="color: green;"></span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> <span style="color: green;">// Perform tasks</span></pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum6" style="color: #606060;"> 6:</span> iisProcess.Start();</pre>
</div>
</div>
<br />
Now PowerShell:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> stop-service <span style="color: #006080;">"IISADMIN"</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> # Perform tasks</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> start-service <span style="color: #006080;">"IISADMIN"</span></pre>
</div>
</div>
<br />
<h2>
Modifying the web.config</h2>
Unfortunately, I couldn’t find a way of using the in-built System.Configuration classes to open configuration files that are outside of your application. Instead, I just resorted to XmlDocument:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> var location = <span style="color: #006080;">"d:\\web.config"</span>;</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> var newTimeout = <span style="color: #006080;">"20"</span>;</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> var xmlDoc = <span style="color: blue;">new</span> XmlDocument();</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> xmlDoc.Load(location);</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum6" style="color: #606060;"> 6:</span> xmlDoc.SelectSingleNode(<span style="color: #006080;">"//sessionState"</span>).Attributes[<span style="color: #006080;">"timeout"</span>].Value = newTimeout;</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum7" style="color: #606060;"> 7:</span> xmlDoc.Save(location);</pre>
</div>
</div>
<br />
I know what your thinking. How can we access the file in PowerShell? One of the fantastic things with PowerShell is that you have access to all of the .NET classes (including static methods and classes) at your disposal. So here is the same code in PowerShell:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> # Set values </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> $location = <span style="color: #006080;">"d:\web.config"</span></pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> $newTimeout = <span style="color: #006080;">"20"</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> # Open file and change value</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum6" style="color: #606060;"> 6:</span> $doc = new-object System.Xml.XmlDocument</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum7" style="color: #606060;"> 7:</span> $doc.Load($location)</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum8" style="color: #606060;"> 8:</span> $doc.SelectSingleNode(<span style="color: #006080;">"//sessionState"</span>).timeout = $newTimeout </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum9" style="color: #606060;"> 9:</span> $doc.Save($location)</pre>
</div>
</div>
<br />
Notice how I am using a “timeout” variable directly. PowerShell has exposed the attribute as a property of the <code>.SelectSingleNode()</code> method. How do I know that? Well, if you execute this in isolation, you’ll get a nice helpful output on all of the properties available to use directly:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;">PS C:\> $doc.SelectSingleNode(<span style="color: #006080;">"//sessionState"</span>)</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;">timeout #text</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;">------- -----</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;">20 20</pre>
</div>
</div>
<br />
Now we have a PowerShell script in its entirety:<br />
<br />
<br />
<div id="codeSnippetWrapper">
<br />
<div id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; overflow: visible; padding: 0px; text-align: left; width: 100%;">
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> # PowerShell script <span style="color: blue;">to</span> modify the 'timeout' value <span style="color: blue;">in</span> the specified web.config</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> # when no Sessions are <span style="color: blue;">in</span> use.</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> # Constants used throughout application</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> $webConfig = <span style="color: #006080;">"d:\web.config"</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum6" style="color: #606060;"> 6:</span> $newTimeout = <span style="color: #006080;">"20"</span></pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum7" style="color: #606060;"> 7:</span> $sessionCount = 0</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum8" style="color: #606060;"> 8:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum9" style="color: #606060;"> 9:</span> ## BEGIN</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum10" style="color: #606060;"> 10:</span> write-host Getting performance counters ...</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum11" style="color: #606060;"> 11:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum12" style="color: #606060;"> 12:</span> $perfCounterString = <span style="color: #006080;">"\asp.net applications(__total__)\sessions total"</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum13" style="color: #606060;"> 13:</span> $perfCounter = get-counter -counter $perfCounterString </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum14" style="color: #606060;"> 14:</span> $rawValue = $perfCounter .CounterSamples[0].CookedValue </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum15" style="color: #606060;"> 15:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum16" style="color: #606060;"> 16:</span> write-host Session Count is $rawValue</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum17" style="color: #606060;"> 17:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum18" style="color: #606060;"> 18:</span> <span style="color: blue;">if</span>( $rawValue -gt $sessionCount)</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum19" style="color: #606060;"> 19:</span> {</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum20" style="color: #606060;"> 20:</span> write-host Session Count = $rawValue - exiting</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum21" style="color: #606060;"> 21:</span> <span style="color: blue;">exit</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum22" style="color: #606060;"> 22:</span> }</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum23" style="color: #606060;"> 23:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum24" style="color: #606060;"> 24:</span> write-host Stopping IIS</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum25" style="color: #606060;"> 25:</span> stop-service <span style="color: #006080;">"IISAdmin"</span></pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum26" style="color: #606060;"> 26:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum27" style="color: #606060;"> 27:</span> # Open file and change value</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum28" style="color: #606060;"> 28:</span> $doc = new-object System.Xml.XmlDocument</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum29" style="color: #606060;"> 29:</span> $doc.Load($webConfig)</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum30" style="color: #606060;"> 30:</span> $doc.SelectSingleNode(<span style="color: #006080;">"//sessionState"</span>).timeout = $newTimeout </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum31" style="color: #606060;"> 31:</span> $doc.Save($webConfig)</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum32" style="color: #606060;"> 32:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum33" style="color: #606060;"> 33:</span> write-host Starting IIS</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum34" style="color: #606060;"> 34:</span> start-service <span style="color: #006080;">"IISAdmin"</span></pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum35" style="color: #606060;"> 35:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum36" style="color: #606060;"> 36:</span> write-host Done!</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum37" style="color: #606060;"> 37:</span> ## END</pre>
</div>
</div>
<br />
<h2>
Granting permissions to the Script</h2>
We’re not done yet. PowerShell also has a security feature that doesn’t allow users to just run PowerShell scripts as soon as they are created. They have to come from a credible source to be run straight away.<br />
In order to run this script, we need to tell PowerShell to bypass security checks for this specific process (or user). For security reasons, I will grant access for this process, as we will only want to run this script once.<br />
<br />
<ol><br />
<li>Open a Command Prompt – Right Click – Properties - "Run As Administrator" </li>
<li>Type <code>powershell.exe</code> </li>
<li>Type <code>Set-ExecutionPolicy –scope Process Bypass</code> </li>
<li>Type <code>sl <directory of file></code> – <code>sl</code> acts like <code>cd</code> on the command prompt </li>
<li>Type <code>$ ‘.\ChangeIIS.ps1’</code></li>
</ol>
And off we go!<br />
<br />
<h2>
Summary </h2>
Where opportunities arise to try out new technologies, it is always work having a go. PowerShell isn’t difficult to learn. In fact, its actually very powerful and intuitive. It is also a great ‘Immediate Window’ style interface to try out .NET code. I’m starting to use it quite a lot for even simple calculations:<br />
<br />
<br />
<div style="text-align: center;">
<kbd>2<sup>24</sup> ==> [System.Math]::Pow(2,24)</kbd></div>
<br />
And more importantly – I hope I win that bounty question!<br />
<br />
<br />
<hr />
<br />
<br />
<h3>
Recent Edits:</h3>
<br />
<ul><br />
<li>28/3/12 - Changed performance counter to use "Sessions Active" instead of "Sessions Total" as Sessions Total inclues Abandoned (forcefully ended), Timed Out and Active.</li>
</ul>Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com1tag:blogger.com,1999:blog-318959828636418328.post-47195779263814280752012-02-27T22:20:00.001+00:002012-02-28T07:55:52.657+00:00How do you test a project without affecting the database?Today I sat with a colleague and went through how we could implement testing on existing code, without affecting the data in the database. For anyone who answers that question the words “Dependency Injection” – well done! Maybe this post isn’t for you! <img alt="Smile with tongue out" class="wlEmoticon wlEmoticon-smilewithtongueout" src="http://lh4.ggpht.com/-nT4tz7-6bXE/T0wBpmzd61I/AAAAAAAAGOg/WhFzGR3OtL4/wlEmoticon-smilewithtongueout%25255B2%25255D.png?imgmax=800" /><br />
But I wanted to give anyone asking themselves this question a short guide on how to get this working, as it is a common problem faced when adapting an existing project to include unit testing. <br />
<h2>
An example</h2>
So first of all, lets get some basic code together to try this out:<br />
<br />
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> Model
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> User
{
<span style="color: blue;">public</span> User (<span style="color: blue;">int</span> userId) { <span style="color: blue;">this</span>.UserId = userId; }
<span style="color: blue;">public</span> <span style="color: blue;">int</span>? UserId { get; <span style="color: blue;">private</span> set;}
<span style="color: blue;">public</span> <span style="color: blue;">string</span> UserName { get; set; }
<span style="color: blue;">public</span> <span style="color: blue;">string</span> Password { get; set; }
}
}</pre>
<br />
Next, lets pretend we’ve got some existing DB code, possibly Entity Framework, to get this data out of the database:</div>
<br />
<div>
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> DataAccess
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> SqlRepository : DbContext
{
<span style="color: blue;">public</span> User CreateUser() { <span style="color: green;">/*..*/</span> }
<span style="color: blue;">public</span> User ReadUser(<span style="color: blue;">int</span> id) { <span style="color: green;">/*..*/</span> }
<span style="color: blue;">public</span> <span style="color: blue;">void</span> UpdateUser(User userToUpdate) { <span style="color: green;">/*..*/</span> }
<span style="color: blue;">public</span> <span style="color: blue;">void</span> DeleteUser(<span style="color: blue;">int</span> userId) { <span style="color: green;">/*..*/</span> }
}
}</pre>
</div>
<br />
<div>
You also have a Business Logic layer, which will interface with the SqlRepository for us. For simplicity, I will only deal with the UpdateUser() method:</div>
<br />
<div>
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> Logic
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> UserService
{
<span style="color: blue;">private</span> SqlRepository repository = <span style="color: blue;">null</span>;
<span style="color: blue;">public</span> UserService()
{
<span style="color: blue;">this</span>.repository = <span style="color: blue;">new</span> SqlRepository();
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> UpdateUser(User updatedUser)
{
<span style="color: blue;">if</span> ( updatedUser == <span style="color: blue;">null</span> )
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> ArgumentNullException(<span style="color: #006080;">"updatedUser"</span>);
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> ( updatedUser.UserId == <span style="color: blue;">null</span> )
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> ArgumentException(<span style="color: #006080;">"UserId must be set."</span>);
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> ( String.IsNullOrEmpty(updatedUser.UserName) )
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> ArgumentException(<span style="color: #006080;">"Username is not valid."</span>);
}
<span style="color: blue;">else</span> <span style="color: blue;">if</span> ( !PasswordIsComplexEnough( updateUser.Password ) )
{
<span style="color: blue;">throw</span> <span style="color: blue;">new</span> PasswordNotSecureException(<span style="color: #006080;">"Password must meet the minimum security requirements."</span>);
}
<span style="color: blue;">else</span>
{
<span style="color: blue;">this</span>.repository.UpdateUser (updatedUser);
}
}
}
}</pre>
</div>
<br />
<div>
Now when we get to writing integration tests, we’ll find that we update users directly in the database, leaving the database in a possibly invalid state. A test might take the format of:<br />
<br /></div>
<div>
<div id="codeSnippetWrapper">
<div id="codeSnippetWrapper">
<div>
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> Tests.Integration
{
[TestClass]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> UserServiceTests
{
[TestMethod]
<span style="color: blue;">public</span> <span style="color: blue;">void</span> WhenAServiceIsCreated_AndAnExistingUserIsUpdated_TheUserIsSavedSucessfully()
{
<span style="color: green;">// Arrange</span>
var userService = <span style="color: blue;">new</span> Logic.UserService();
var existingUser = userService.ReadUser(1);
existingUser.Password = StringFunctions.BuildRandomString(50); <span style="color: green;">// 50 chars of text</span>
<span style="color: green;">// Act</span>
userService.UpdateUser ( existingUser );
<span style="color: green;">// Assert - assume we have implemented Equals() to compare their content</span>
var updatedUser = userService.ReadUser(1);
Assert.AreNotEqual(existingUser, updatedUser);
}
}
}</pre>
</div>
<br />
<div>
The problem is now, you’ve wiped the password for that user. If it is hashed in the database, you have no way of retrieving it without modifying it manually. I suppose you could re-apply the original user, but then you are now having to do a tidy up exercise after every test. If another test depends on that user account being valid (e.g. a UI test to log that user in), then you’re going to fail more tests and the problem will only get worse.<br />
<hr />
</div>
<h2>
Dependency Injection</h2>
Dependency Injection allows us to “inject” the database we would like to modify. Some developers like to have their own database that can be freely modified whenever. But in the long term, the maintenance of tidying this database, coupled with the speed of database connections for thousands of tests becomes unmanageable. Ideally, you want these tests to pass as soon as possible so you can get on with your work. <br />
<br />
<div>
But as this code stands, we will always point at the database. So we’ll need to do some slight modifications to get this code more flexible, without breaking existing code.</div>
<br />
<span style="font-size: large;">Step 1 – Extract an interface</span><br />
<br />
<div>
The easiest step is to use Visual Studio to extract an interface for you. You do this by right clicking on the class name of the DataAccess layer > Refactor > Extract Interface</div>
</div>
<br />
<div>
<a href="http://lh5.ggpht.com/-exoGy4GKg9E/T0wBqkqeoiI/AAAAAAAAGOo/EWeFMkFic0c/s1600-h/blog%25255B8%25255D.jpg"><img alt="blog" border="0" height="250" src="http://lh5.ggpht.com/-FspMr3ies6c/T0wBrs5u4yI/AAAAAAAAGOw/-CHa25-uY38/blog_thumb%25255B6%25255D.jpg?imgmax=800" style="background-image: none; border-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="blog" width="784" /></a></div>
</div>
<br />
Once you’ve clicked “Select All” and “OK”, this gives you your current code, implementing a newly created interface, which I will rename IRepository (and make public).<br />
<br /></div>
<div id="codeSnippetWrapper">
<div id="codeSnippetWrapper">
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> DataAccess
{
<span style="color: blue;">public</span> <span style="color: blue;">interface</span> IRepository
{
User CreateUser();
<span style="color: blue;">void</span> DeleteUser(<span style="color: blue;">int</span> userId);
User ReadUser(<span style="color: blue;">int</span> id);
<span style="color: blue;">void</span> UpdateUser(User userToUpdate);
}
<span style="color: blue;">public</span> <span style="color: blue;">class</span> SqlRepository : DbContext, IRepository
{
<span style="color: green;">/* As before */</span>
}
}</pre>
</div>
<div>
<br />
So now we have the ability to create a TestRepository, based on IRepository, that can act like a database. So lets quickly make a TestRepository:</div>
<br />
<div id="codeSnippetWrapper">
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> Tests.Helper
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> TestRepository : IRepository
{
<span style="color: green;">/** Methods leaving the NotImplementedException code in place **/</span>
}
}</pre>
</div>
<br />
<hr />
<br />
<h3>
Step 2 - Adapt the service layer to accept an IRepository</h3>
</div>
<br />
Next, we adapt the UserService class to accept a new parameter, to allow us to “inject” the database into the class. This way, existing code still works and the test code can take advantage of the new constructor.<br />
<br />
<div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> UserService
{
<span style="color: blue;">private</span> <strong><span style="background-color: yellow;">IRepository</span></strong> repository;
<span style="color: blue;">public</span> UserService() :
<span style="color: blue;">this</span> ( <span style="color: blue;">new</span> SqlRepository() )
{
}
<strong><span style="color: blue;"><span style="background-color: yellow;">internal</span></span> </strong>UserService (IRepository injectedRepository)
{
<span style="color: blue;">this</span>.repository = injectedRepository;
}
<strong><span style="color: #408080;"> /* As before */</span></strong>
}</pre>
<br />
Notice I’m using an <strong>internal </strong>constructor intentionally, as I don’t want to expose this to just anyone. What I can do is instruct the CLR that <strong>internal</strong>s are <strong>visible to </strong>another assembly. This is done in the AssemblyInfo.cs class for the DataAccess layer like this:</div>
<br />
<div>
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;">[assembly: InternalsVisibleTo(<span style="color: #006080;">"Tests"</span>)]</pre>
</div>
<br />
Note that I have used the Assembly Name of the assembly to which the internal fields, properties, methods and constructors can be accessed. <br />
<hr />
<br />
<h3>
Step 3 - Inject the new repository</h3>
Now, we are able to modify our test to pass in the TestRepository class we created, so that when the UserService is created, it will access our implementation. </div>
<br />
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> Tests.Integration
{
[TestClass]
<span style="color: blue;">public</span> <span style="color: blue;">class</span> UserServiceTests
{
[TestMethod]
<span style="color: blue;">public</span> <span style="color: blue;">void</span> WhenAServiceIsCreated_AndAnExistingUserIsUpdated_TheUserIsSavedSucessfully()
{
<span style="color: green;">// Arrange</span>
var userService = <span style="color: blue;">new</span> Logic.UserService(<span style="background-color: yellow;"><span style="color: blue;">new</span> TestRepository()</span>);
var existingUser = userService.ReadUser(1);
existingUser.Password = StringFunctions.BuildRandomString(50); <span style="color: green;">// 50 chars of text</span>
<span style="color: green;">// Act</span>
userService.UpdateUser ( existingUser );
<span style="color: green;">// Assert - assume we have implemented Equals() to compare their content</span>
var updatedUser = userService.ReadUser(1);
Assert.AreNotEqual(existingUser, updatedUser);
}
}
}</pre>
<br />
Now – okay – the application will throw an exception! Because we haven’t implemented the TestRepository class and left it at its default implemention, the methods will throw errors. But by writing some simple code, which does as much as we need to get going, we no longer rely on running our tests through the DB:</div>
<br />
<div>
<div>
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">namespace</span> Tests.Helper
{
<span style="color: blue;">public</span> <span style="color: blue;">class</span> TestRepository : IRepository
{
<span style="color: blue;">private</span> List<User> users = <span style="color: blue;">null</span>;
<span style="color: blue;">public</span> TestRepository() { users = <span style="color: blue;">new</span> List<Users>(); }
<span style="color: blue;">public</span> <span style="color: blue;">void</span> UpdateUser(User user)
{
var storedUser = users.Where(u => u.UserId == user.UserId).SingleOrDefault();
<span style="color: green;">// Do some exception handling here, just to throw an error if it doesn't exist.</span>
<span style="color: green;">// This way it 'sort-of' acts like a database.</span>
storedUser.UserName = user.UserName;
storedUser.Password = user.Password;
}
}
}</pre>
</div>
<br />
And now we have a testable repository.<br />
<br />
There are frameworks called Mocking frameworks, that can even alleviate you of this burden. But I’ve yet to explore them enough to include in this blog.<br />
<br />
<h3>
Summary</h3>
<br />
In this blog, we have looked at a common example that many developers face. We have adapted the existing functionality, <strong><em>without breaking existing code</em></strong>, but extending it for use with a testing framework.<br />
<div>
This adaptation allows you to concentrate on testing all of those permutations within the UserService, which is what we actually want to test.</div>
<br />
<div>
I will adapt a full tutorial of this blog, so that users can try out the refactoring for themselves.</div>
</div>
</div>
</div>Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-52760654537870075532012-02-19T11:15:00.001+00:002012-02-28T07:56:10.604+00:00How to implement best practices with the .NET FrameworkOne area that I know I’ve needed to improve is implementing some best practices within a team of developers.<br />
The areas I am aiming to improve are:<br />
<ol>
<li>Developers being forced to use a code analysis tool, instead of ignoring the warnings </li>
<li>Run unit tests or integration tests on a regular basis without developer intervention </li>
<li>A way to build, package and deploy them without user intervention – including databases </li>
<li>A report to generate automated processes </li>
<li>(Optional) Developers following some kind of coding convention </li>
</ol>
My only interaction with any tool that pulls this together (via manual intervention to my experience) was Team Foundation Server. Since this was the choice of most clients I had worked with, I was interested in improving my own skills so that when new or existing projects come along, I could implement some standards. Therefore code quality and development become my main priorities. Manual intervention would be little or none.<br />
I have read Rapid Development by Steve McConnell. This book to me was a bible of information on project management, team building and development practices. However I found that many of the examples were widely applicable, giving no examples of technologies due to its generality. RD is very broadly applicable to all development practices, but with this purchase I was specifically looking for something with products, processes and examples to implement them with.<br />
I’ve started reading a book called <a href="http://www.amazon.co.uk/NET-Best-Practices-Stephen-Ritchie/dp/1430240237/ref=pd_rhf_cr_p_t_1" target="_blank">Pro .NET Best Practices</a> and this was <strong><em>exactly </em></strong>what I was after.<br />
<em>‘Best Practices’</em> is not a term the author chooses to use. Instead, he chose <a href="http://ruthlesslyhelpful.net/" target="_blank">‘Ruthlessly Helpful’ – the title of his blog site</a>. <br />
<em>‘Best’</em> implies there is nothing better. However, a ‘<em>better</em>’ practice may suffice as each practice is different to one another. Some work better with small teams, some with bigger teams. The author chose ‘Ruthless’ – something that requires thought and consideration which will be able to you and your team size.<br />
But by adding ‘Helpful’ also implies that the process will only serve as a <em>benefit </em>to you and your team. Whether you want to reduce bugs, improve product delivery or automate your deployment, any helpful practice is one worthy of consideration.<br />
And so the term ‘Ruthlessly Helpful’ was born. <br />
Pro .NET Best Practices covers a whole plethora of information for applying the development lifecycle properly. Everything from the tools used for development of the product, right through to the deliverable. This book isn’t another book full of code examples – although many are provided for clarity. The books goal is to educate and motivate readers on better practices of software development.<br />
I see it has all 5 star ratings on the <a href="http://www.amazon.com/NET-Best-Practices-Stephen-Ritchie/dp/1430240237/ref=sr_1_sc_1?ie=UTF8&qid=1329650057&sr=8-1-spell" target="_blank">Amazon.com</a> site. And it is well deserved!Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-23028550451818519362012-02-01T22:37:00.001+00:002012-02-01T22:59:27.617+00:00Restricting URL access without using the web.config<p>I’ve been lucky enough to work with 2 major clients that do <em>not</em> use the out-of-the-box user-role association of security. If your site is not restricted by a user’s role or user name, how do you implement security? Good question!</p> <p>So some examples of custom URL authorization is:</p> <ul> <li>Access to a page is not determined solely on a role or username.</li> <li>Allow admins to change web page access permissions on-the-fly from a maintenance page.</li> <li>Allow pages to be restricted via a timeframe. Admin users may still be allowed access after working hours.</li></ul> <h2>An example</h2> <p>Imagine a site that has 4 user roles:</p> <ul> <li>Manager <li>Supervisor <li>Employee <li>Administrator</li></ul> <p>You might have a requirement that:</p> <blockquote> <p>“An access control page needs to be created so that we (the administrators) can select the permissions of the pages through a UI. One week we might decide to extend a supervisors to a subset of the manager pages. These changes may be permanent or temporary. Either way we need an admin screen to selectively choose the permissions for each page from an admin screen and restrict access this way.”</p></blockquote> <p>Equipped with your vast ASP.NET knowledge, you could advise them to create an intermediate role of “Super-supervisor” and use web.config files to restrict user access. Responses are:</p> <ul> <li>The existing system embeds the role so tightly, that this requires too much work to implement across the business logic and reporting structure. <li>Changes to web.config to incorporate page access will require direct access to the Web box. Our application’s sys admins are not technical users and could bring down the site. <li>We have already decided to split the site into 3 sections – Public, Secure and Admin sections. However you choose to implement it, this is the only 3 categories we care about. <li>We also want the sitemap to update dynamically with these changes.</li></ul> <p>So lets see what API we could use …. hmmm … unfortunately:</p> <ul> <li>Membership providers only help us identify who a logged in user is – no go. <li>Role providers only help us identify what role a specific user has – no go.</li></ul> <p>What we need is a way to check the access types allowed <em>upon</em> <em>access</em> to a page. Then restrict page from there.</p> <h2>How does ASP.NET do it?</h2> <p>It does so by use of the <a href="http://msdn.microsoft.com/en-us/library/system.web.security.urlauthorizationmodule.aspx" target="_blank">UrlAuthorizationModule</a>, which looks through the Web.config locating the page or directory. Then using the defined rules, it will either allow access, or send a 401 (Unauthorized) response to the pipeline. Later on in the pipeline, the FormsAuthenticationModule sees the 401 and pushes them to the login screen.</p> <p>Good news is works in a very similar way to how we want. Sadly, it isn’t inheritable so we have to roll our own one. So lets have a stab at it.</p> <h2>Rolling our on UrlAuthorizationModule</h2> <p>Modules work by plugging into the HTTP pipeline for all requests. So just implement <font face="Courier New">IHttpModule</font>, add code to the <font face="Courier New">Init </font>method, and hook into the <font face="Courier New">AuthorizeRequest </font>event.</p> <p> <div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> CustomUrlAuthorizationModule : IHttpModule<br>{<br> <span style="color: #0000ff">private</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> Unauthorised = 401;<br><br> <span style="color: #cc6633">#region</span> IHttpModule Members<br><br> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Dispose()<br> {<br> <span style="color: #008000">// Do nothing</span><br> }<br><br> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Init(HttpApplication context)<br> {<br> context.AuthorizeRequest += <span style="color: #0000ff">new</span> EventHandler(context_AuthorizeRequest);<br> }<br><br> <span style="color: #0000ff">void</span> context_AuthorizeRequest(<span style="color: #0000ff">object</span> sender, EventArgs e)<br> {<br> <span style="color: #008000">// Work out access from the URL</span><br> }<br><br> <span style="color: #cc6633">#endregion</span><br>}</pre><br></div>Nearly there! Okay, so the second-to-last thing you need to do is look at the page coming in, get the information about what users/roles can access that page. So here’s some sample code for it.<br /><br /><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">void</span> context_AuthorizeRequest(<span style="color: #0000ff">object</span> sender, EventArgs e)<br>{<br> var context = HttpContext.Current;<br> <br> <span style="color: #008000">// Use custom logic to determine access criteria</span><br> <span style="color: #0000ff">bool</span> accessAllowed = IsUserAuthorizedToSeePage(<br> context.User.Identity.IsAuthenticated, <br> context.User.Identity.Name,<br> context.Request.Path);<br><br> <span style="color: #0000ff">if</span> (accessAllowed)<br> {<br> <span style="color: #0000ff">return</span>;<br> }<br> <span style="color: #0000ff">else</span><br> {<br> <span style="color: #008000">// Set status code to 'Unauthorized' and bypass all other components</span><br> context.Response.StatusCode = 401;<br> context.ApplicationInstance.CompleteRequest();<br> }<br>}</pre><br></div><br /><p>And lastly, some sample logic to check if a user has access:</p><br /><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">private</span> <span style="color: #0000ff">bool</span> IsUserAuthorizedToSeePage(<span style="color: #0000ff">bool</span> isAuthenticated, <span style="color: #0000ff">string</span> userName, <span style="color: #0000ff">string</span> url)<br>{<br> <span style="color: #0000ff">using</span>(Data.DbEntities db = <span style="color: #0000ff">new</span> Data.DbEntities())<br> { <br> var dbUrl = db.PageAccess.Where(row => row.PageUrl.Equals(url,StringComparison.OrdinalIgnoreCase)).FirstOrDefault();<br><br> <span style="color: #0000ff">if</span>(dbUrl == <span style="color: #0000ff">null</span>)<br> {<br> logger.Error(<span style="color: #006080">"Cannot find access rights for {0}"</span>, url);<br> <span style="color: #0000ff">return</span> DenyAccess(<span style="color: #006080">"Page access rights cannot be found."</span>);<br> }<br> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (dbUrl.Public)<br> {<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;<br> }<br> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span>(!isAuthenticated)<br> {<br> logger.Warn(<span style="color: #006080">"Unauthenticated request for URL {0}"</span>,url);<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br> }<br> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span>(dbUrl.Secure) <br> {<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;<br> }<br> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (dbUrl.Admin)<br> {<br> var userInfo = db.Users.Where(user => user.UserName == userName).FirstOrDefault();<br><br> <span style="color: #0000ff">if</span> (userInfo == <span style="color: #0000ff">null</span>)<br> {<br> logger.Error(<span style="color: #006080">"Cannot find access rights for {0} to {1}"</span>, userName, url);<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br> }<br> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (userInfo.Role == <span style="color: #006080">"Admin"</span>)<br> {<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;<br> }<br> <span style="color: #0000ff">else</span><br> {<br> logger.Warn(<span style="color: #006080">"User {0} attempted to access {1}, but was disallowed due to access rights"</span>, userName, url);<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br> }<br> }<br> <span style="color: #0000ff">else</span><br> {<br> logger.Error(<span style="color: #006080">"Unable to determine if user should access page. User: {0} -- URL: {1}"</span>, userName, url);<br> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br> }<br>}</pre></div><br /><p>And that’s all you need to do really. I pull the role out of the database, but if you have decided to store the users role in Session, you can still pull their roles through from the <font face="Courier New">HttpContext.Current.Session</font> object.</p><br /><p>(BTW, the “logger” would be some implementation of a logger, I use <a href="http://nlog-project.org/" target="_blank">NLog</a>)</p> Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-57496837634793199962011-04-14T22:48:00.002+01:002012-02-27T22:45:19.014+00:00Inner controls not populating when using UserControls within UserControlsI spent some time writing a new component converting our existing use of a free <a href="http://www.basicdatepicker.com/BDPLite/" target="_blank">BDPLite</a> component, which I wanted to replace with a <a href="http://jqueryui.com/demos/datepicker/" target="_blank">jQuery UI DatePicker</a> control.<br />
I created a basic control, and injected some JavaScript into the page for the jQuery control<br />
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><%@ Control .... %>
<div <span style="color: blue;">class</span>=<span style="color: #006080;">"datePickerDiv"</span>>
<input type=<span style="color: #006080;">"text"</span> ID=<span style="color: #006080;">"txtDate"</span> <span style="color: blue;">class</span>=<span style="color: #006080;">"datePicker"</span> runat=<span style="color: #006080;">"server"</span>/>
</div></pre>
</div>
Code to insert the code once per page:<br />
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">protected</span> <span style="color: blue;">void</span> Page_Load(<span style="color: blue;">object</span> sender, EventArgs e)
{
<span style="color: blue;">if</span> (!Page.ClientScript.IsClientScriptBlockRegistered(<span style="color: blue;">this</span>.GetType(), <span style="color: #006080;">"jQuery"</span>))
{
Page.ClientScript.RegisterClientScriptBlock(
<span style="color: blue;">this</span>.GetType(),
<span style="color: #006080;">"jQuery"</span>,
<span style="color: #006080;">@"$(document).ready( function() { $("</span><span style="color: #006080;">".datePicker"</span><span style="color: #006080;">").datepicker(); });"</span>,
<span style="color: blue;">true</span>);
}
}</pre>
</div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<br />
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">public</span> DateTime? SelectedDate
{
get
{
DateTime dateTime;
<span style="color: blue;">if</span>(!DateTime.TryParseExact(<span style="color: blue;">this</span>.txtDate.Value, <span style="color: #006080;">"dd/MM/yyyy"</span>, <span style="color: blue;">out</span> dateTime))
<span style="color: blue;">return</span> <span style="color: blue;">null</span>;
<span style="color: blue;">else</span>
<span style="color: blue;">return</span> dateTime;
}
set
{
<span style="color: blue;">this</span>.txtDate.Value = <span style="color: blue;">value</span>.ToString(<span style="color: #006080;">"dd/MM/yyyy"</span>);
}
}</pre>
</div>
Now, assuming:</div>
</div>
<ul>
<li>We’ve added our jQuery references at the top of the page too and it is all working fine</li>
<li>We’re creating a new control in the same directory as the old one e.g. ~/usercontrols</li>
<li>We are referencing the DatePicker control in another control</li>
</ul>
Here is another control, referencing the first one<br />
<div class="csharpcode-wrapper">
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="background-color: yellow;"><%@ Control ....%></span>
<span style="background-color: yellow;"><%@ Register TagPrefix="ct1" TagName="DatePicker" Src="~/usercontols/DatePicker.ascx" %></span>
<span style="color: blue;"><</span><span style="color: maroon;">div</span> <span style="color: red;">class</span><span style="color: blue;">="outerControl"</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">ct1:DatePicker</span> <span style="color: red;">runat</span><span style="color: blue;">="server"</span> <span style="color: red;">ID</span><span style="color: blue;">="dtDate"</span> <span style="color: blue;">/><</span><span style="color: maroon;">br</span><span style="color: blue;">/></span>
<span style="color: blue;"><</span><span style="color: maroon;">ct1:DatePicker</span> <span style="color: red;">runat</span><span style="color: blue;">="server"</span> <span style="color: red;">ID</span><span style="color: blue;">="dtDate2"</span> <span style="color: blue;">/><</span><span style="color: maroon;">br</span><span style="color: blue;">/></span>
<span style="color: blue;"></</span><span style="color: maroon;">div</span><span style="color: blue;">></span></pre>
</div>
</div>
<br />
<div class="csharpcode-wrapper">
And you try and set some default values up in code:</div>
<br />
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: green;">// Set default values for controls.</span>
<span style="color: blue;">protected</span> <span style="color: blue;">void</span> Page_Load(<span style="color: blue;">object</span> sender, EventArgs e)
{
dtDate.SelectedDate = DateTime.Now;
dtDate2.SelectedDate = DateTime.Now.AddDays(1);
}</pre>
</div>
<br />
<div class="csharpcode-wrapper">
You’ll find you’ll get a NullReferenceException at this line:</div>
<div class="csharpcode-wrapper">
<br /></div>
<div class="csharpcode-wrapper" id="codeSnippetWrapper">
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="color: blue;">if</span>(!DateTime.TryParseExact(<span style="color: blue;">this</span>.txtDate.Value, <span style="color: #006080;">"dd/MM/yyyy"</span>, <span style="color: blue;">out</span> dateTime))</pre>
<br /></div>
Or more specifically – at <strong><em>txtDate</em></strong><br />
The short answer is that .NET (4.0 anyway) doesn’t like you referencing controls within controls when they are of the same folder level. I’m not 100% sure at this exact second if it matters if they are in the same namespace.<br />
But to fix this, I moved it to a sub-directory, changed the namespace name and changed the reference and voila! It all worked fine.</div>Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-77183535072479510242011-04-13T21:55:00.004+01:002011-04-14T22:56:15.824+01:00Unity and ASP.NET MVC 2 Controller injection<p>I’ve been reading a brilliant <a href="http://www.amazon.co.uk/ASP-NET-Framework-Experts-Voice-NET/dp/1430228865/ref=pd_sim_b_1" target="_blank">ASP.NET MVC Framework V2 Book</a> by Steven Sanderson and found that he uses NInject DI framework with MVC. So I thought I’d give it a go with Unity – and it actually isn’t that bad.</p> <p>So the things we need are: </p> <ol> <li>An interface declaration defining the contract that the concrete class should meet. Also implementation of the controller. </li><li>A DI framework (Unity) to carry out the injection </li><li>A Controller Factory to provide the DI framework with the controller to populate. </li><li>Attach the custom factory to the MVC framework.</li></ol> <p>So, I won’t provide huge amounts of code for the interface/class implementations, but here is a quick example:</p> <h2>Step 1 – Create an interface, class and controller implementation</h2> <div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Consolas', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">interface</span> IProductsRepository<br />{<br /> IQueryable<Product> Products { get; }<br />}<br /><span style="color: #008000">//</span><br /><span style="color: #0000ff">class</span> SqlDbRepository: DbContext, IProductsRepository<br />{<br /> IQueryable<Product> Products { get; }<br /> <span style="color: #008000">// implementation here</span><br />}<br /><span style="color: #008000">//</span><br /><br /><span style="color: #0000ff">class</span> ProductsController : Controller<br />{<br /><span style="color: #0000ff">private</span> IProductsRepository productsRepository;<br /><br /><span style="color: #0000ff">public</span> ProductsController (IProductsRepository repository)<br />{<br /> <span style="color: #0000ff">this</span>.productsRepository = repository; <br />}<br />}</pre></div><h2>Step 2 - Configure the Unity container</h2><p>Now, create the mapping in the configuration file. I find this the hardest way, hence why I do it :-P</p><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Consolas', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff"><</span><span style="color: #800000">configSections</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">section</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="unity"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"</span> <span style="color: #0000ff">/></span><br /><span style="color: #0000ff"></</span><span style="color: #800000">configSections</span><span style="color: #0000ff">></span><br /><br /><span style="color: #0000ff"><</span><span style="color: #800000">unity</span> <span style="color: #ff0000">xmlns</span><span style="color: #0000ff">="http://schemas.microsoft.com/practices/2010/unity"</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">alias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="IProductsRepository"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="SportsStore.Domain.Abstract.IProductsRepository,SportsStore.Domain"</span><span style="color: #0000ff">/></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">alias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="SqlDbRepository"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="SportsStore.Domain.Concrete.SqlDbRepository,SportsStore.Domain"</span><span style="color: #0000ff">/></span><br /><br /> <span style="color: #0000ff"><</span><span style="color: #800000">container</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">register</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="IProductsRepository"</span> <span style="color: #ff0000">mapTo</span><span style="color: #0000ff">="SqlDbRepository"</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">=""</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">lifetime</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="singleton"</span><span style="color: #0000ff">/></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">constructor</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">param</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="connectionStringName"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="string"</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">="Default"</span> <span style="color: #0000ff">/></span><br /> <span style="color: #0000ff"></</span><span style="color: #800000">constructor</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"></</span><span style="color: #800000">register</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"></</span><span style="color: #800000">container</span><span style="color: #0000ff">></span><br /><span style="color: #0000ff"></</span><span style="color: #800000">unity</span><span style="color: #0000ff">></span><br /><br /><span style="color: #0000ff"><</span><span style="color: #800000">connectionStrings</span><span style="color: #0000ff">></span><br /> <span style="color: #0000ff"><</span><span style="color: #800000">add</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="Default"</span> <span style="color: #ff0000">connectionString</span>='<span style="color: #ff0000">Data</span> <span style="color: #ff0000">Source</span>=.\<span style="color: #ff0000">SQLEXPRESS</span>;<span style="color: #ff0000">AttachDbFilename</span>="&<span style="color: #ff0000">amp</span>;<span style="color: #ff0000">lt</span>;<span style="color: #ff0000">path</span> <span style="color: #ff0000">to</span><span style="color: #0000ff">></span>\SportsStore.mdf";Integrated Security=True;User Instance=True' providerName='System.Data.SqlClient'<span style="color: #0000ff">/></span><br /><span style="color: #0000ff"></</span><span style="color: #800000">connectionStrings</span><span style="color: #0000ff">></span></pre></div><p>I admit, the configuration looks scary. But I am just <register> ing an interface to a class.</p><ul><li><alias> means I don’t have to retype the fully qualified type every time I want to use it.<br /></li><li>I am ‘injecting’ a <constructor> <param> eter into the SqlDbRepository class with the <value=“Default”/>. My <code>SqlDbRepository</code> is based on the <code>DbContext</code> class which accepts the connection string name, which the Entity Framework uses to look up the actual connection string.</li></ul><p>Lets get some code together to initialise the UnityContainer…</p><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #008000">// Create a container</span><br />IUnityContainer container = <span style="color: #0000ff">new</span> UnityContainer();<br /><br /><span style="color: #008000">// Get the section and apply it to the container.</span><br />UnityConfigurationSection section = ConfigurationManager.GetSection(<span style="color: #006080">"unity"</span>) <span style="color: #0000ff">as</span> UnityConfigurationSection;<br />section.Configure(container);</pre></div><br /><p>Next, we need some code that will apply this mapping (<code>IProductsRepository</code> to <code>SqlDbRepository</code>) to a given object. So I give it an object that has an <code>IProductsRepository</code> constructor parameter. It will then return me an initialised instance of that object, with the <code>SqlDbRepository</code> passed directly into it.</p><h2>Step 3 – Create a custom ControllerFactory to populate the controllers</h2><p>MVC have a class called the “DefaultControllerFactory”, which has a method called “GetControllerInstance”. This method is used to create a new instance of a given controller type. So for example, when initialising a ProductsController controller, this method is fired with</p><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Consolas', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> IController GetControllerInstance(RequestContext context, Type controllerType)<br />{ <br /><span style="color: #008000">// controllerType == ProductsController</span><br />}</pre><br /><p>Therefore, if we want to create a ProductsController created with the IProductsRepository constructor parameter populated, we just call the .Resolve() method.</p><p>This method takes a Type object and says .. “hmmm .. interesting, having a look over you, I see you have an IProductsRepository constructor parameter. Veeryyy interesting …. Now the thing is, I’ve been configured to pass in a …….. SqlDbRepository object … to a constructor which requires IProductsRepository“ .. So it creates a SqlDbRepository class (with constructor parameters specified earlier), injects it into the constructor, creating a new instance of the ProductsController class.</p><p>Now once that Resolve() has returned, it needs to be cast to an IController (i.e. the interface of Controller i.e. the parent class of ProductsController).</p><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Consolas', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> UnityControllerFactory : DefaultControllerFactory<br />{<br /><span style="color: #0000ff">private</span> IUnityContainer unityContainer;<br /><br /><span style="color: #0000ff">public</span> UnityControllerFactory(IUnityContainer container)<br />{<br /> <span style="color: #0000ff">this</span>.unityContainer = container;<br />}<br /><br /><span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> IController GetControllerInstance(RequestContext requestContext, Type controllerType)<br />{<br /> <span style="color: #0000ff">return</span> unityContainer.Resolve(controllerType) <span style="color: #0000ff">as</span> IController;<br />}<br />}</pre><h2>Step 4 – Attach the custom ControllerFactory to the framework</h2><p>And finally, we have to tell MVC that when creating controllers, use this ControllerFactory to populate them. So in Global.asax, I do:</p><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Consolas', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> Application_Start()<br />{<br /> AreaRegistration.RegisterAllAreas();<br /> RegisterRoutes(RouteTable.Routes);<br /><br /> <span style="color: #008000">// From earlier</span><br /> IUnityContainer container = <span style="color: #0000ff">new</span> UnityContainer();<br /> UnityConfigurationSection section = ConfigurationManager.GetSection(<span style="color: #006080">"unity"</span>) <span style="color: #0000ff">as</span> UnityConfigurationSection;<br /> section.Configure(container);<br /><br /> <span style="color: #008000">// Configure framework to populate using my controller factory</span><br /> UnityControllerFactory unity = <span style="color: #0000ff">new</span> UnityControllerFactory(container);<br /> ControllerBuilder.Current.SetControllerFactory(unity);<br />}</pre><p>Job done!</p>Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-35340774270768617572011-04-12T14:00:00.001+01:002012-02-28T07:58:09.239+00:00Debug and Trace messages not showing in DebugView after upgrading to .NET 4.0Just a heads up to anyone upgrading to .NET 4.0, and finding their debugging not working. <br />
I have been spending the day scratching our heads over why our stage deployment isn’t writing debugging messages to <a href="http://technet.microsoft.com/en-us/sysinternals/bb896647" target="_blank">DebugView</a>, after a recent upgrade to .NET 4.0. Before, in v1.1, v2.0 and v3.5 it was working fine, so why has it stopped now? <br />
We have since found that functionality <a href="https://connect.microsoft.com/VisualStudio/feedback/details/457063/outputdebugstring-doesnt-work-in-the-debugger-vs-2010-pro-beta-1-c">was removed from .NET 4.0</a> – therefore is by-design. <br />
If you have any applications which use: <code> </code><br />
<code></code><br />
<code>Debug.Write(); <br />Debug.WriteLine(); <br />Debug.Print(); <br />Trace.Write(); <br />Trace.WriteLine(); <br />Trace.Print(); </code><br />
These will only appear while Visual Studio is debugging the application. For any environment where you are not doing any attach-to-process managed debugging, you see nothing. <br />
Therefore, you may have to investigate one of the many logging applications e.g. <br />
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/ff664569(PandP.50).aspx" target="_blank">Logging Application Block</a> </li>
<li><a href="http://sourceforge.net/projects/log4net/" target="_blank">Log4Net</a></li>
</ul>
However, the <code>System.Diagnostics.DefaultTraceListener</code> will still not render any output, when configured by these frameworks.Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-46823999509158377722010-11-16T15:53:00.001+00:002012-02-27T22:45:39.283+00:00GridView fires a RowCommand event when the paging is triggered?Yes, very odd behaviour this one. <br />
I guess the assumption is that RowXXXXX events relate to Row events - selection, creation, deletion, editing. But <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand.aspx"><code>RowCommand</code> </a>actually caters for <em>any</em> button that is clicked on a <code>GridView</code>.<br />
Therefore paging controls are buttons, and therefore fire the <code>RowCommand</code> event with the <code>CommandSource</code> as "Page".<br />
Therefore something like this will always fire both events:<br />
<code></code><br />
<code><pre><div id="codeSnippetWrapper" style="background-color: #f4f4f4; border: 1px solid silver; cursor: text; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 20px 0px 10px; max-height: 200px; overflow: auto; padding: 4px; text-align: left; width: 97.5%;">
<pre id="codeSnippet" style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span style="background-color: yellow;"><%@Page Language="C#" AutoEventWireup="true"%></span>
<span style="color: blue;"><</span><span style="color: maroon;">script</span> <span style="color: red;">runat</span><span style="color: blue;">="server"</span><span style="color: blue;">></span><pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum1" style="color: #606060;"> 1:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum2" style="color: #606060;"> 2:</span> <span style="color: blue;">protected</span> <span style="color: blue;">void</span> Page_Load(<span style="color: blue;">object</span> sender, EventArgs e)</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum3" style="color: #606060;"> 3:</span> {</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum4" style="color: #606060;"> 4:</span> <span style="color: blue;">if</span>(!IsPostBack)</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum5" style="color: #606060;"> 5:</span> {</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum6" style="color: #606060;"> 6:</span> ArrayList list = <span style="color: blue;">new</span> ArrayList();</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum7" style="color: #606060;"> 7:</span> list.Add ( <span style="color: #006080;">"Item1"</span> );</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum8" style="color: #606060;"> 8:</span> list.Add ( <span style="color: #006080;">"Item2"</span> );</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum9" style="color: #606060;"> 9:</span> list.Add ( <span style="color: #006080;">"Item3"</span> );</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum10" style="color: #606060;"> 10:</span> list.Add ( <span style="color: #006080;">"Item4"</span> );</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum11" style="color: #606060;"> 11:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum12" style="color: #606060;"> 12:</span> <span style="color: blue;">this</span>.GridView1.DataSource = list;</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum13" style="color: #606060;"> 13:</span> <span style="color: blue;">this</span>.GridView1.DataBind();</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum14" style="color: #606060;"> 14:</span> }</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum15" style="color: #606060;"> 15:</span> }</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum16" style="color: #606060;"> 16:</span> </pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum17" style="color: #606060;"> 17:</span> <span style="color: blue;">protected</span> <span style="color: blue;">void</span> RowCom( <span style="color: blue;">object</span> sender, GridViewRowCommandArgs e)</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum18" style="color: #606060;"> 18:</span> {</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum19" style="color: #606060;"> 19:</span> Page.Controls.Add ( <span style="color: blue;">new</span> Label(<span style="color: #006080;">"Row_Command fired => CommandSource = "</span> + e.CommandSource) );</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum20" style="color: #606060;"> 20:</span> }</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum21" style="color: #606060;"> 21:</span> </pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum22" style="color: #606060;"> 22:</span> <span style="color: blue;">protected</span> <span style="color: blue;">void</span> Row_Index( <span style="color: blue;">object</span> sender, GridViewPageIndexChangedCommandArgs e)</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum23" style="color: #606060;"> 23:</span> {</pre>
<pre style="background-color: #f4f4f4; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum24" style="color: #606060;"> 24:</span> Page.Controls.Add ( <span style="color: blue;">new</span> Label(<span style="color: #006080;">"PageIndexChanged fired"</span>) );</pre>
<pre style="background-color: white; color: black; direction: ltr; font-family: "Courier New", courier, monospace; font-size: 8pt; line-height: 12pt; margin: 0em; overflow: visible; padding: 0px; text-align: left; width: 100%;"><span id="lnum25" style="color: #606060;"> 25:</span> }</pre>
<span style="color: blue;"></</span><span style="color: maroon;">script</span><span style="color: blue;">></span>
<span style="color: blue;"><</span><span style="color: maroon;">asp:GridView</span>
<span style="color: red;">runat</span><span style="color: blue;">="server"</span>
<span style="color: red;">ID</span><span style="color: blue;">="GridView1"</span>
<span style="color: red;">OnRowCommand</span><span style="color: blue;">="RowCom"</span>
<span style="color: red;">OnPageIndexChanging</span><span style="color: blue;">="Row_Index"</span>
<span style="color: red;">EnablePaging</span><span style="color: blue;">="true"</span> <span style="color: red;">PageSize</span><span style="color: blue;">="2"</span><span style="color: blue;">></span>
<span style="color: blue;"></</span><span style="color: maroon;">asp:GridView</span><span style="color: blue;">></span></pre>
</div>
</pre>
</code>Therefore, you have to ensure that in the RowCommand, that you only filter the events which you want, rather than assuming only row clicks will come through this event.Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-9478485435023192022010-07-30T15:30:00.003+01:002010-07-30T15:34:01.125+01:00How to kill a process in SQL Server 2005 Process with ID –2<p>Recently, I encountered the problem where a transaction had been left open and therefore was causing issues with a specific table in the database. When looking at the SSMS in Maintenance –> Activity Monitor, the tables were being locked by Process ID –<strong>2</strong>. Normally you would kill processes by using the:</p> <code>kill xx</code> <p>e.g.</p> <code>kill –2</code><div><br /></div><div><code></code>Unfortunately, the kill command only allows you to kill process above 0. So how do you kill it? <p>The other way to kill processes is to use the GUID assigned to the process, which is found if you scroll slightly to the right. Like this</p> <img src="http://1.bp.blogspot.com/_I13gV_vlrcc/TFLiRM7gjKI/AAAAAAAAFlo/J2zwxGc-eoY/s320/guid.jpg" style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 95px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5499706880129272994" /><p><br /></p><p><br /></p><p><br /></p><p><br /></p><p>Although the GUID here is all zeroes (possibly because it is an internal process locking it), this is the GUID you use. So the command would look something like:</p> <code>kill '4ab0d37b-566d-44ab-8396-4d35a53f955b'</code> <p>After executing it in the Query Window, you should find the locks are released, but note that since you have killed the transaction, the data changes will be rolled back.</p></div>Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-69884112103942437802010-06-22T11:36:00.002+01:002010-06-22T11:38:03.311+01:00iPhone 0S4 update is taking too long to backup<p>So after downloading the iPhone OS 4, the backup begins – and well – is still around 5% after 3 1/2 hours.</p> <p>I read a <a href="http://discussions.apple.com/thread.jspa?threadID=2469437&tstart=0" target="_blank">suggestion from the Apple Forums</a>, to do the following:</p> <blockquote> <ol> <li>Cancel the backup </li> <li>Manually backup your iphone through itunes.</li> <li>Then restore iphone. An option will come up that says "restore and update". </li> <li>Iphone reboots after installation of os4. Then restore from backup in itunes</li> </ol> <p>That process took about 30 minutes and I was done. </p> </blockquote> <p>And I can verify that it does indeed! </p>Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-21431712722604540132010-06-21T17:56:00.001+01:002010-06-21T17:57:21.974+01:00Why and where is my XmlSerializer failing?<h2>Overview</h2> <p>The <code>XmlSerializer</code> is an excellent utility to turn your classes into XML and vice versa very very easily. So long as you aren't using it on dynamically generated types, but are repeatedly on the same types, then the XML serializer is quite performant.</p> <p>However, as great as the XmlSerializer is, I’ve found it a pain to debug. You have 2 choices:</p> <ol> <li>Look through the XML and find the invalid field <li>Step through every property in the debugger for your class and find the property that is failing </li></ol> <h2>Problem</h2> <p>When your XML document gets to the point of having hundreds of elements, this becomes a real problem. You’ll see output like this:</p><kbd><pre style="overflow: auto">Writing to Application log: System.InvalidOperationException: There is an error in XML document (1, 10433). <br /> ---> System.FormatException: Input string was not in a correct format. <br /> at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) <br /> at System.Number.ParseDecimal(String value, NumberStyles options, NumberFormatInfo numfmt) <br /> at System.Xml.XmlConvert.ToDecimal(String s) <br /> at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderCustomer.Read3_Customer(Boolean isNullable, Boolean checkType) <br /> at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderCustomer.Read4_Customer() <br /> --- End of inner exception stack trace --- <br /> at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) <br /> at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader) <br /> at BusinessObjects.SerializationUtils.Deserialize[T](T& typeOfObject, String xml) <br /> at WebServices.Customer.ImportCustomer(XmlDocument xml) in C:\MyWebServices\CustomerTest\Customer.asmx.cs:line 43 </pre></kbd><br /><p>Now you see the problem. The XML indicates (1, 10433) , which would indicate my XML has be reduced to 1 line, trimming the spaces. and then column 10433. It turns out this is incorrect as my XML at this location was this:</p><kbd><pre></ns0:CreditLimit><ns<span style="background-color: yellow">0</span>:LastPaymentDate></pre></kbd><br /><p>..And obviously this is wrong. Totally valid XML wise, its just something cannot be parsed to a Decimal.</p><br /><h2>Solution</h2><br /><p>Since XmlSerializer generates physical code, which is then compiled on-the-fly, I was looking for a way to gain access to this file. Upon finding the location, Visual Studio 2008 doesn't realise that the file links to the PDB generated by the XmlSerializer compilation proces. </p><br /><p>After a little digging, I've found that Scott Hanselman blogged about <a href="http://www.hanselman.com/blog/HOWTODebugIntoANETXmlSerializerGeneratedAssembly.aspx" target="=_new">debugging the XmlSerializer serialization process in .NET</a>, which is exactly what I was looking to do.</p><br /><p>He says to add some entries to the related configuration file like:</p><br /><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff"><?</span><span style="color: #800000">xml</span> <span style="color: #ff0000">version</span><span style="color: #0000ff">="1.0"</span> <span style="color: #ff0000">encoding</span><span style="color: #0000ff">="utf-8"</span> ?<span style="color: #0000ff">></span><br><span style="color: #0000ff"><</span><span style="color: #800000">configuration</span><span style="color: #0000ff">></span><br> ...<br> <span style="color: #0000ff"><</span><span style="color: #800000">system.diagnostics</span><span style="color: #0000ff">></span><br> <span style="color: #0000ff"><</span><span style="color: #800000">switches</span><span style="color: #0000ff">></span><br> <span style="color: #0000ff"><</span><span style="color: #800000">add</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="XmlSerialization.Compilation"</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">="1"</span> <span style="color: #0000ff">/></span><br> <span style="color: #0000ff"></</span><span style="color: #800000">switches</span><span style="color: #0000ff">></span><br> <span style="color: #0000ff"></</span><span style="color: #800000">system.diagnostics</span><span style="color: #0000ff">></span><br> ...<br><span style="color: #0000ff"></</span><span style="color: #800000">configuration</span><span style="color: #0000ff">></span></pre><br></div><br /><p>This then allows you to open the file from the temporary directory C:\Documents And Settings\[user]\Local Settings\Temp after the <code>new XmlSerializer(Type t)</code> is executed. When the <code>.Deserialize()</code> method is called, you will find you can Step Into (!!) the code generated. The best thing about this, is that since the PDB is now linked together with the code, your stack traces are much more helpful:</p><kbd><pre style="overflow: auto">.... as before but ....<br />at MS.XML.GeneratedAssembly.XmlSerializationReaderCustomer.Read3_Customer(Boolean isNullable, Boolean checkType) <span style="background-color: yellow">in c:\Documents and Settings\ASPNET\Local Settings\Temp\dcvrxygb.0.cs:line 985 </span><br />at MS.XML.GeneratedAssembly.XmlSerializationReaderCustomer.Read4_Customer() <span style="background-color: yellow">in c:\Documents and Settings\ASPNET\Local Settings\Temp\dcvrxygb.0.cs:line 163 </span><br />.........</pre></kbd><br /><p>Woohoo!! So we now have line numbers, and if we open up the source code we see .....</p><br /><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (.....)<br>{<br> o.@TaxRate = System.Xml.XmlConvert.ToDecimal(Reader.ReadElementString());<br>}<br>...</pre><br></div><br /><p>And we look at my XML element TaxRate (as they are a direct mapping and we find ....</p><br /><div id="codeSnippetWrapper"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 12pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff"><</span><span style="color: #800000">ns0:TaxRate</span><span style="color: #0000ff">></span>??<span style="color: #0000ff"></</span><span style="color: #800000">ns0:TaxRate</span><span style="color: #0000ff">></span></pre><br></div><br /><p>Spot the problem ;-) </p> Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0tag:blogger.com,1999:blog-318959828636418328.post-5198216230014334482010-06-21T17:54:00.002+01:002010-07-09T10:28:11.885+01:00How to find out if there are items for an EnumerableRowCollection<p>Unfortunately, this class doesn’t have a .Count() method, so you have to do a horrible hack to find out if there are items.</p> <p>I suppose you could implement it as an Extension method, but as it is, this is what you need to do:</p> <div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; padding-left: 4px; width: 97.5%; padding-right: 4px; direction: ltr; color: #f4f4f4; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; background-: 20px 0px 10px" id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible"><span style="color: #008000">// Create table and populate data</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible">DataTable dt = <span style="color: #0000ff">new</span> DataTable();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible">dt.Columns.Add(<span style="color: #006080">"Column1"</span>,<span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">string</span>));</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible">dt.Rows.Add( <span style="color: #0000ff">new</span> <span style="color: #0000ff">object</span>[] { <span style="color: #006080">"sample1"</span> });</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible"> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible"><span style="color: #008000">// Filter by a non-existent field, so now dataRows is now an </span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible"><span style="color: #008000">// EnumerableRowCollection with no rows</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible">var dataRows = from row <span style="color: #0000ff">in</span> dt.AsEnumerable()</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; border-left-style: none; overflow: visible; padding-top: 0px" color="black" size="8pt" face="'Courier New', courier, monospace"> <span style="color: #0000ff">where</span> row.Field<<span style="color: #0000ff">string</span>>(<span style="color: #006080">"Column1"</span>) eq <span style="color: #006080">"FAKE DATA"</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible"> select row;</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; border-left-style: none; overflow: visible; padding-top: 0px" color="black" size="8pt" face="'Courier New', courier, monospace"> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible"><span style="color: #008000">// This next line throws an InvalidOperationException </span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #008000">//// DataTable filteredResults = dataRows.CopyToDataTable(); </span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; border-left-style: none; overflow: visible; padding-top: 0px" color="black" size="8pt" face="'Courier New', courier, monospace"> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #008000">// Instead, create a new IEnumerator and iterate through it manually.</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; border-left-style: none; overflow: visible; padding-top: 0px" color="black" size="8pt" face="'Courier New', courier, monospace">IEnumerator iEnum = dataRows.GetEnumerator();</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; direction: ltr; border-top-style: none; border-left-style: none; overflow: visible; padding-top: 0px" color="black" size="8pt" face="'Courier New', courier, monospace"><span style="color: #0000ff">if</span>(!iEnum.MoveNext())</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{ </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> ShowMessage(<span style="color: #006080">"No data available"</span>);}</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">} </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">else</span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> DataTable filteredResults = dataRows.CopyToDataTable(); </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #008000">// More DataTable processing here .... </span></pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> MyGridView1.DataSource = filteredResults; </pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> MyGridView1.DataBind();}</pre><!--CRLF--><pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre><!--CRLF--></div></div><br><br /><p>It is nasty, but it works :-)</p> Anonymoushttp://www.blogger.com/profile/04445725709903156963noreply@blogger.com0