Tuesday, August 11, 2009

Separating MVC Projects in a WCF World

I'm working on a new ASP.NET MVC project where the business logic is all in a separate WCF services layer. Thus, our controllers orchestrate the UI and communicate to the controllers for the business logic.
Most simple MVC books and tutorials show a single project with separate folders for the Model, Views and Controllers. If you read long enough, you'll find suggestions of splitting the Model, Views and Controllers into their own projects/assembles. Normally, a strongly-typed View would depend on the Model. A Controller would prepare the Model for the View, so it too would depend on the Model. But the Model never depends on the View nor the Controller. We've attempted this on our project, but we hit a snag.
The Controller project has service references to our WCF services. Service references conveniently generate client proxies the services and their data transfer objects right inside the Controller project. These DTOs often suffice for a Model for our Views. However, there are many places where our Views need a more View-friendly Model, so we adpat some of those DTOs into UI-specific Model classes housed in our Model project.
The problem comes when our UI-specific Model needs to contain some of the DTOs. Because the UI-specific Model classes are in the Model project, but the classes our service references convienently generated for us are in the Controller project, you can't dot his without having an assembly reference from Model to Controller. This breaks the rule that the Model should not depend upon anything.
My short-term solution has been to do away with the separate Model project and just house the UI-specific Model classes in the Controller project, alongside the generated classes. I've not yet settled on a long-term solution. Splitting up the generated code (that is, splitting the generated service client and the generated data classes) seems futile. Perhaps the generated data classes shouldn' be used as a Model, but instead each one should have its own UI-specific counterpart in a separate Model project. Time to ponder...

Monday, August 3, 2009

ASP.NET Multi-environment Deployment Configuration

I'm still new to ASP.NET, fresh off of the JEE bandwagon. In many ways, deploying an ASP.NET application to IIS can be blazingly simple (e.g. "just copy the built artifacts to the site folder"). Like JEE, though, there doesn't seem a good, widely agreed upon solution for separating environment-specific configuration from the application-specific configuration.

Like many shops, we have several environments. We have two "debug" environments and two "non-debug" environments where we want things quiet and locked down. The "debug" environments can show full exception detail, verbose logging, etc. The "non-debug" environments -- including production -- do not. Our UAT environment is configured as a "non-debug" environment so that its as close to how it will be experienced in production as possible. Furthermore, the databases, internal URLs and such also vary from environment to environment.

Most of the solutions I came across suggested maintaining multiple web.configs, one for each environment. I dislike such solutions because it requires duplicate maintenance (I'm lazy, and humans inevitably fail to do the "dual" part). I did find one suggestion I liked: use XSL transformation to modify points in your web.config for each environment.

Thus far, I have crafted an XML stylesheet for our dev and uat environments. Each of these is designed to transform our web.config from source control (set up for local environments) into a configuration specific to that environment. The stylesheet itself largely clones the existing XML, replacing specific values or attributes, such as:

  • Connection strings (substituting variables where necessary)
  • Exception detail (toggled on or off)

  • Debuggable ASPx compilation (toggled on or off)

  • WCF service endpoint addresses (URLs specific to each environment)

  • Logging listener log file paths

  • etc.

For example, to turn off debug information for the pages, the following snippet is used:

    <!-- Set the debug compilation to enable/disable insertion of debugging symbols into the compiled page. Because this affects performance, set this value to true only during development. -->

    <xsl:template match="/configuration/system.web/compilation/@debug">

      <xsl:attribute name="debug">true</xsl:attribute>


I've also broken my stylesheets into a base one for the web.config (e.g. my AppServices project's stylesheet is AppServices.xsl) as well as an environment-specific stylesheet that sets the variables for it (e.g. AppServices-dev.xsl, AppServices-uat.xsl):

    <xsl:variable name="logRoot" select="'\inetpub\logs\AppLogs\CIN2010\Dev\AppServices'" />

    <xsl:include href="./AppServices.xsl" />

Thus far, the plan is working quite well. The Hudson CI server is building and automatically deploying the applications, transforming the web.config as it goes. From time-to-time I have to alter the stylesheets to extract another environment-specific setting, but this is rare and straight forward.

Damn DRM

With my new Nokia 5800 XpressMusic came a composite video and stereo audio output cable. This wasn't a feature I had required of my new phone, but it certianly earns it some geek points. It also came with a $50 gfit credit for Amazon's Unbox video service. I eagerly downloaded Dr. Horrible which I heard heard so much about.
After watching Dr. Horrible on my phone, I next wanted to try playing it to my TV via TVersity. However, TVersity couldn't handle transcoding whatever format Amazon delivered it in. A week later, I tried plugging the A/V output cable into my TV directly, only to find a black screen with an icon in the middle: a key with a slash through it -- no doubt a culturally agnostic way of telling me the content was locked.
So I plan to let the rest of my $50 gift credit go to waste because it turns out $50 of Amazon Unbox video content isn't worth a dime.