# 10 Kasım 2008 Pazartesi
I'm sure someone did this before, but I'm too lazy to search for it :)

Model Binders in MVC is a cool concept to map your form values to parameter objects of your Action. There's also this automatic error message display capabilities in MVC. All explained by The Gu here.

Here's my take on validating a model object during the binding process. Castle project has a validation framework and a range of validators which can be used standalone. It would be cool to use it with MVC to ease the validation pain a bit, huh?

First, we need a binder to validate the object using Castle's ValidatorRunner:

    using System.Web.Mvc;
    using Castle.Components.Validator;
 
    public class ValidatingModelBinder : DefaultModelBinder
    {
        public override ModelBinderResult BindModel(ModelBindingContext bindingContext)
        {
            var result = base.BindModel(bindingContext);
 
            if (result != null && result.Value != null)
            {
                var runner = new ValidatorRunner(new CachedValidationRegistry());
                if (!runner.IsValid(result.Value))
                {
                    var summary = runner.GetErrorSummary(result.Value);
                    foreach (var invalidProperty in summary.InvalidProperties)
                    {
                        foreach (var error in summary.GetErrorsForProperty(invalidProperty))
                        {
                            bindingContext.ModelState.AddModelError(bindingContext.ModelName + "." + invalidProperty, error);
                        }
                    }
                }
            }
 
            return result;
        }
    }

And an object to validate:

    using Castle.Components.Validator;
 
    public class CreateUser
    {
        [ValidateNonEmpty("Please enter user name.")]
        public string UserName { get; set; }
        [ValidateNonEmpty("Please enter password.")]
        public string Password  { get; set; }
        [ValidateEmail("Email is not valid.")]
        [ValidateNonEmpty("Please enter email address.")]
        public string Email { get; set; }
    }

And an action to use the object:

        public ActionResult CreateUser(CreateUser createUser)
        {
            if (ViewData.ModelState.IsValid)
            {
                ViewData["Message"] = "Done.";
            }
 
            return View();
        }

Please note that, when the action is invoked, parameter is already validated. We just check ViewData.ModelState.IsValid and act accordingly.

Next, we'll tell the MVC engine to bind CreateUser objects through ValidatingModelBinder, in Application_Start() of Global.asax.cs:

        ModelBinders.Binders.Add(typeof(CreateUser), new ValidatingModelBinder());

So, whenever the engine is bindign to a CreateUser, our binder will execute (and validate) the object. Finally, code below for the view:

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <%if (ViewData["Message"] != null)
      {%>
        <%=ViewData["Message"]%>
    <%} %>
    <%=Html.ValidationSummary() %>
    <form method="post" action="/Home/CreateUser">
        User name: <br />
        <%=Html.TextBox("CreateUser.UserName")%>  <%=Html.ValidationMessage("CreateUser.UserName", "*")%><br />
        Password: <br />
        <%=Html.Password("CreateUser.Password")%> <%=Html.ValidationMessage("CreateUser.Password", "*")%><br />
        Email: <br />
        <%=Html.TextBox("CreateUser.Email")%> <%=Html.ValidationMessage("CreateUser.Email", "*")%><br />
        <input type="submit" value="Submit" />
    </form>
</asp:Content>

Here's the result:

posted on 10 Kasım 2008 Pazartesi 10:40:43 UTC  #   
# 04 Kasım 2008 Salı
Update: Check the comment by Matt Hinze. It appears that we don't need this kind of complexity after Preview 4. Check this and this, for example. Thanks Matt. My lesson? When you're using pre-release software with lots of changes and improvements in each release, be sure to reevaluate all your past assumptions in each.

--

Just a note. I use a base like this code to avoid repetitive test setup when testing MVC controllers.

    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using MbUnit.Framework;
    using Rhino.Commons;
    using Rhino.Mocks;
 
    public abstract class ControllerTestBase<TController> 
        where TController : Controller
    {
        protected TController controller;
        protected ControllerContext controllerContext;
        protected IDisposable disposeGlobalUnitOfWorkRegistration;
        protected HttpContextBase httpContextStub;
        protected HttpSessionStateBase httpSessionStub;
        protected IUnitOfWork unitOfWorkStub;
 
        [SetUp]
        public virtual void Setup()
        {
            SetupController();
 
            unitOfWorkStub = MockRepository.GenerateStub<IUnitOfWork>();
            httpContextStub = MockRepository.GenerateStub<HttpContextBase>();
            httpSessionStub = MockRepository.GenerateStub<HttpSessionStateBase>();
            httpContextStub.Stub(x => x.Session).Return(httpSessionStub);
            var httpRequestStub = MockRepository.GenerateStub<HttpRequestBase>();
            httpContextStub.Stub(x => x.Request).Return(httpRequestStub);
            controllerContext = new ControllerContext(httpContextStub, new RouteData(), controller);
            controller.ControllerContext = controllerContext;
            disposeGlobalUnitOfWorkRegistration = UnitOfWork.RegisterGlobalUnitOfWork(unitOfWorkStub);
        }
 
        protected abstract void SetupController();
 
        [TearDown]
        public void TearDown()
        {
            disposeGlobalUnitOfWorkRegistration.Dispose();
        }
    }


Then...


    using System.Web.Mvc;
    using Common;
    using Core.Authentication;
    using Core.Repositories;
    using Domain.Entities;
    using MbUnit.Framework;
    using Rhino.Commons;
    using Rhino.Mocks;
    using UI.Controllers;
    using UI.Properties;
 
    [TestFixture]
    public class RegisterControllerTests : ControllerTestBase<RegisterController>
    {
        private IRepository<User> repositoryStub;
        private IAuthenticationService authServiceStub;
 
        protected override void SetupController()
        {
            repositoryStub = MockRepository.GenerateStub<UserRepository>();
            authServiceStub = MockRepository.GenerateStub<IAuthenticationService>();
            controller = new RegisterController(repositoryStub, authServiceStub);
        }
 
        [Test]
        public void Will_display_error_message_if_logged_in()
        {
            authServiceStub.Stub(c => c.IsAuthenticated()).Return(true);
            var result = controller.Index() as RedirectToRouteResult;
            Assert.IsNotNull(result);
            var message = controller.TempData["Message"] as string;
            Assert.IsFalse(string.IsNullOrEmpty(message));
            Assert.AreEqual(GlobalResources.CannotRegisterAlreadyRegistered, message);
            Assert.AreEqual(result.Values["action"], "Index");
            Assert.AreEqual(result.Values["controller"], "Message");
        }
    }
posted on 04 Kasım 2008 Salı 20:32:02 UTC  #   
# 26 Haziran 2008 Perşembe
For VS2008: ActiveWriter Preview 4.1.rar (282.73 KB)
I'm not updating 2005 version anymore.

What's New:
  • Optionally generates classes implementing INotifyPropertyChanging.
  • Contrib-117: Database and designer column order is not in sync
Fixed:
  • Added "Nested" to Common.ARAttributes (Patch: Roberto Paterlini)
  • Swapped parameters in new ArgumentNullException (Patch: Roberto Paterlini)
  • Changed in-memory code compilation error reporting to give full details of the internal compile process. No more ExceptionCollection's.
  • Contrib-118: Activewriter errors in combination with VisualSVN (Patch: Visual SVN Team)
  • Changed the temporary file generation to use \obj folder rather than arbitrary locations on the system.


posted on 26 Haziran 2008 Perşembe 11:21:59 UTC  #   
Or Omea Reader has a strange dependency on Firefox:)

If, after upgrading to Firefox 3, your Omea Reader stops downloading feeds with the error message someting like "Could not find file C:\Documents and Settings\<your user name>\Application Data\Mozilla\Profiles\<random>.default\cookies.txt", that's because Firefox 3 now employs cookies.sqlite to persist cookie info. Create an empty cookies.txt there to get Omea on it's feet again. By the way, I tried to switch to Google Reader while investigating this problem and didn't found it as useful as Omea. Other than some odd behavior after resuming the computer from hibernation, and the lack of online reading experience from different macgines :(, Omea is still the perfect blog reader for me.

Now, depending on the existence of a cookies file of an external application is a shame on JetBrains's part, on the other hand. Especially if a dummy file works just as expected.

posted on 26 Haziran 2008 Perşembe 11:00:46 UTC  #   
Kathleen Dollard wrote a response regarding the Vote of No Confidence on the Entity Framework. I was reading her post knowing that there will be lots of posts circling around the Vote of No Confidence, some will agree and some won't, and that was such a post from a particular point of view, until I hit this one (emphesis not mine):
"Entity approaches are good because they better separate the business and data sides of our middle tiers. But they are also inherently difficult and inaccessible to most programmers. Entity Framework’s goal must be to bridge this gap. That means being extremely creative in picking its battles to reach toward the real world developer – not copy a strategy that is available to that developer today and fails (the combination of NHibernate and other tools used in a specific style of development). The failure is not because NHibernate is an Open Source tool. It’s not because people don’t know about it. If it worked in the majority of shops it would burn through our industry like wildfire. Why don’t you use them? Because they do not fit your development environment!"
Sorry, but this is FUD or what? What's the ground here to say that NHibernate, or any O/RM approach mimicking it, is failing? Does Linq To SQL, which is no different in theory than NHibernate but lacks most of it's features, is a carrot from MS to the impatient while they wait for the uber EF framework? What makes something fail in MS land when it is actually quite successful in other platforms? Take TDD, for example. It works, appearently, and gaining some momentum. But it's nowhere near burning through our industry like wildfire. You can't make average Joe and his boss accept TDD as the defacto way of writing software. Does that mean TDD fails? Do we need some other über-TDD to replace it at the moment?

NHibernate does actually fit very well into my development environment, and I see no reason why it won't for any other developer. It has a clear SoC attitude, minimalistic configuration (compare NH xml configuration files with any behind-the-scene xml dialect from MS and you'll know what I mean), nice performance. It has everything if you want to write maintainable code. That does not mean that it's irreplaceable, but it just works, now, and any newcomer should challange it, not vice versa.

But yes, it does not fit the development environment often thought by Microsoft. Last year, I have paid a visit to a client who was suffering lots of performance, scalability and mainly maintainability problems with their in-house written ERP system. It turns out that, the application was built on typed datasets start to finish. They decided that they need to port their application to .Net, took some courses along with MOC 2541 (part of the official MS curriculum saying that data access is a solved problem if you use drag'n drop and datasets), realized that typed datasets is the ultimate-easy way do access data and the rest is history for them. Don't get me wrong, I instructed almost all the courses in the official MS curriculum, but in each case I mentioned and demoed alternatives and told the audience that what they see in the official book is just part of the story.

In the last couple years I'm feeling much better about Microsoft, the direction they're heading, the way they're interacting with and listening to the community. I'm also a firm believer in code generation when it's due, wrote some tools to make developers' life easier (including people using NHibernate), and actually paid a visit to Cambidge, UK to meet the nice people of the DSL Tools team for a job interview a couple of months ago (I failed, appearently). I'm buying the toy my son wanted by spending the money I earned by using Microsoft technologies, and I'm happy with what I do. But I can't stand the "MS way or nothing else" attitude.

Microsoft is famous for handling developers as babies sometimes. If you're a C# developer, create a VB.NET project and you'll see that behavior precisely. In a VB.Net project, why project references or .designer.cs files are hidden? Where all this namespace thing gone? Where's the damn entry point of this application? The broad, ignorant world of MS developer echosystem (of which I'm a part of) is actualy ignorant because of this simple fact. In the past, we are always told that there's a specific way of writing applications, and you can find tools and documentation from Microsoft if you want to know what it is. If there's a problem already solved, it's solved by Microsoft. It's comfortable to leave the thinking to someone else and do what you told.

But times are changing, DAL == DAAB no more, we are more open and influenced by other tools, platforms and thinking. This is also true for O/RM tools / frameworks. I visit lots of clients every week, and O/RM is really something people are researching or already using somehow, be it in-house, EF, Linq to SQL, LLBLGen, NHibernate, or something else. So, again, how can one say that NHibernate is done, kaput, arrivederci? It's all just started, and minds are shifting.

In the long-run, reaching real world developers only works if you solve their real world problems with long-lasting frameworks. And by long-lasting, I mean frameworks that survive rewrites, gives you the opportunity to say that "I was right by selecting this" three years after your first deployment. I'm not saying that EF is not one of them, but we have seen many palliative solutions from MS that didn't last long, and the items in that Vote of No Confidence document are real and learned by experience. Real world experience.

posted on 26 Haziran 2008 Perşembe 08:49:33 UTC  #   
# 21 Nisan 2008 Pazartesi
Some time ago, Stuart Kent published the roadmap for DSL Tools. The idea of Dsl extensibility and WPF-based design surface mentioned there easily make someone drool. In the comments to the same post, he also mentions a way to provide your own editor instead of the built-in one. Here's my take on using that technique to provide a custom editor-wannabe in WPF.
  • Create a new Domain-Specific Language Designer (File \ New \ Project \ Other Project Types \ Extensibility)
    Name the project as WPFDSLDesigner
  • Select Class Diagrams template and click Finish to accept the defaults.
  • On the DSL Explorer tool window, click on the Editor node. Make a note of the FileExtension property in the Properties Window. Right click Editor node and Delete it.
  • Right click on the WPFDSLDesigner root node and select Add New Custom Editor. Set the FileExtension property. Set Root Class property to ModelRoot.

  • Transform All Templates using the rightmost button on top of the Solution Explorer.
  • Try building the project. The compiler error will lead you to the customization point. The cool thing with the DSL Tools is that, it clearly marks customization points expected by the developer with appropriate comments, all the time. We will add a partial class to supply our own getter in this case, as described by the comment in the code.
  • Add a project reference to WindowsFormsIntegration assembly (The last element in the dialog, most probably)
  • Add a class named WPFDesignerDocView to the DSLPackage project. (I created a DocView folder to group added files in a single place.) Change the code as follows:

    namespace Company.WPFDSLDesigner.DslPackage

    {

        using System.Windows.Forms;

        using System.Windows.Forms.Integration;

     

        internal partial class WPFDSLDesignerDocView

        {

            private ElementHost host;

            public override IWin32Window Window

            {

                get

                {

                    if (host == null)

                    {

                        host = new ElementHost { Dock = DockStyle.Fill };

     

                        WPFDesigner designer = new WPFDesigner(this);

                        host.Child = designer;

                    }

     

                    return host;

                }

            }

     

            protected override bool LoadView()

            {

                bool result = base.LoadView();

                if (result)

                {

                    ((WPFDesigner)host.Child).DocumentLoaded();

                }

     

                return result;

            }

        }

    }

  • Add a User Control (WPF) item to the project, name it WPFDesigner. Change the Xaml code of the UserControl as follows:

    <UserControl x:Class="Company.WPFDSLDesigner.DslPackage.WPFDesigner"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

        <UserControl.Resources>

            <Style TargetType="{x:Type ListBox}">

                <Setter Property="ItemsPanel">

                    <Setter.Value>

                        <ItemsPanelTemplate>

                            <StackPanel />

                        </ItemsPanelTemplate>

                    </Setter.Value>

                </Setter>

                <Setter Property="ItemTemplate">

                    <Setter.Value>

                        <DataTemplate>

                            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5" Margin="6">

                                <Label Content="{Binding Path=Name}"></Label>

                            </Border>

                        </DataTemplate>

                    </Setter.Value>

                </Setter>

            </Style>

        </UserControl.Resources>

     

        <Grid>

            <ListBox Name="modelClassViewer" ItemsSource="{Binding Mode=OneWay}" />

        </Grid>

    </UserControl>

  • And change the code of the UserControl to:

    namespace Company.WPFDSLDesigner.DslPackage

    {

        using Microsoft.VisualStudio.Modeling.Shell;

        using System.Collections.Generic;

     

        public partial class WPFDesigner

        {

            public ModelingDocView DocView { get; set; }

            protected ModelRoot root;

     

            public WPFDesigner()

            {

                InitializeComponent();

            }

     

            public WPFDesigner(ModelingDocView docView)

                : this()

            {

                DocView = docView;

            }

     

            public void DocumentLoaded()

            {

                if (DocView != null && DocView.DocData.RootElement != null)

                {

                    // Had some problems binding to ModelRoot.Types directly. Using a custom list instead.

                    var list = new List<ModelType>();

                    list.AddRange(((ModelRoot)DocView.DocData.RootElement).Types);

                    modelClassViewer.DataContext = list;

                }

            }

        }

    }


  • Your final project structure should be looking something like this:

  • Run the solution to open the Debugging project. Open the Sample.mydslx file. That's all.
And the result is:



Nothing fancy at the moment, but it's pure WPF. Add some compartment shapes and connectors, layout the entities rather than using a StackPanel and you're almost done. Nested shapes and such should be a breeze to implement.

Thank god they're working on this some future version of DSL Tools, WPF is so powerful to customize. I'm expecting that in the final version, we'll optionally be able to provide our own templates instead of the generated ones for customize-like-hell experiences.

Here are some future research points for the implementation above:
  • We can write a code generator to create shapes based on the Diagram Element properties in DslDefinition.dsl. Compartments, decorators, appearance properties etc. Why enumerate a bunch of types at runtime when we're already generating the rest design time?
  • Databinding to LinkedElementCollection failed pretty bad, VS kept crashing in every single case. Hey, I want to use built-in collections. Any INotifyCollectionChanged, by the way?
  • We should be mapping WPF menu items to package menus (VSCT). Add new property, validate etc.
  • We should either use the original .designer file structure to persist the layout etc. or find a way to store that data somewhere. (Designer file is the best)
  • Performance is not so great. I tried some 3D and it's even worse, much worse. There's something fishy going-on when you host a WPF control on top of a win32 container, or in VS, or both.
posted on 21 Nisan 2008 Pazartesi 14:55:54 UTC  #   
# 08 Nisan 2008 Salı
At last. Preview 4 is here. Spread the word :)

I'm very sorry that I couldn't be able to align this release with the Visual Studio 2008 release back in November. I failed to allocate time and couldn't be able to organize people trying to help. Won't do that again.

There are still lots of thing to do but AW is getting much better with each release, thanks to patch submissions and suggestions. Here's the complete what's new list:

New:
  • Added support for Flush for ManyToOneRelation
  • Added partial Oracle drag and drop support. (Patch: Yavor Shahpasov)
  • Generates metadata about properties to be used in queries (as in ICriterion selectCriterium = Expression.Eq(User.Properties.Name, name); )(Thanks: Rudi van den Belt)
  • Contrib-30: Add flag to property to mark it with the DefaultMemberAttribute (or do it by default for primary key fields) (Thanks: Michael Hawksworth)
  • Contrib-50: (Revised description) Allow user defined imports to replace generated imports. (Thanks: Michael Hawksworth)
  • Contrib-54: Integrate NHibernateQueryGenerator into ActiveWriter (Thanks: Steve Degosserie)
  • Contrib-81: Added list relation type. (Patch: Grimace of Despair)
  • Moved all to vS2008
  • Moved binaries license from "as is" to Apache v2. We don't need DSL Tools redistributables in setup package anymore.
Fixed:
  • ManyToOne SourceNotNull is now working propertly
  • Incorrectly generates Some pascal case fields as camel case.
  • Contrib-52: (Revised description) Generic types are incorrectly generated if the given type name already includes generic parameters. (Thanks: Hugo Burm)
  • CONTRIB-59: (Revised description) Problems with NHQG integration when the temporary path, used for out argument, contains spaces. (Patch: Steve Degosserie)
  • Contrib-56: When creating a many-one relation, the generation of the Ilist should always be generic, independent of the generic settings for the objects. (Thanks: Robert van Hoornaar)
  • Contrib-61: (If the namespace cannot be retrieved from the VS project system) When a class is added to a model, the .hbm.xml file that is added as a nested file is missing the first character of the class name in the filename. (Thanks: David Gardiner)
  • Contrib-63: VB projects can have a default root Namespace. ActiveWriter should take this into account when generating the mapping files. It currently appears to only use the model's Namespace property. (Patch: David Gardiner)
  • Contrib-66: The private field used by the relation properties should be initialised with a constructor (Patch: David Gardiner) (Added as a model level option, defaults to false)
  • Contrib-69: Generated VB code should respect project's Option Strict setting (Patch: David Gardiner)
  • Contrib-70: Using a custom type that is defined in a user project fails (Partial patch: David Gardiner)
  • Contrib-72: Option to remove prefix from generated property names.(Patch: David Gardiner) (Implemented as model level RegEx)
  • Contrib-73: Look for Castle.ActiveWriter and NHibernate in project references. (Patch: David Gardiner)
  • Oracle support is now fully working (Patch: Marjan Flis)
There are some bug fixes and improvements in the DSL Tools itself, which directly affects AW. Most notably, the giant red X problem happening time to time when you drag-drop items from Server Explorer is gone with the 2008 release. Another improvement is, DSL Tools redistributables are now included in the IDE, so they're not included in the AW setup, resulting in a smaller download.

Preview 4 will be the last release for VS 2005. It's very hard for me to maintain both 2005 and 2008 versions, so I'm planning to continue with 2008-only releases. But if you encounter a show-stopper bug in 2005 release, I'll fix it.

As always, you can mail me using "gokhan (a) altinoren.com" with all your suggestions and patches.

posted on 08 Nisan 2008 Salı 10:11:14 UTC  #   
# 03 Nisan 2008 Perşembe
It appears that people are having trouble finding templates for some of the documents mentioned in MSF Deliverables Matrix. Here is the Initial Risk Assessment template I created for a client, an excel representation of the ideas in MSF Risk Management Discipline v1.1 document. Enjoy.

Initial Risk Assessment.xlsx (21.81 KB)
posted on 03 Nisan 2008 Perşembe 07:34:26 UTC  #   
# 01 Aralık 2007 Cumartesi
Just for the fun :)



Download: TDDOANG.pdf (734.42 KB)

Notes:
  • Yeah. I know it's not complete / 100% accurate.
  • Yep. There are other tools, I know.
  • Yes, Alt.Net is not the authority. But it's the most active community in MS ecosystem right now where you can ask questions on TDD.
posted on 01 Aralık 2007 Cumartesi 11:29:37 UTC  #   
# 23 Kasım 2007 Cuma
A small tidbit. In WCF, service code like this

public string MyServiceMethod()

{

    throw new FaultException<string>("It happened!");

}


will make VS break into debugger. Normally you just throw FaultException's, knowing that the dispatcher hadles it to convert it to a fault contract message. But VS thinks that it's an unhandled user exception (it is, actualy). For a smoother debugging experience, just add System.ServiceModel.FaultException`1 to Debug / Exceptions / Common Language Runtime Exceptions, unchecked.


posted on 23 Kasım 2007 Cuma 07:07:15 UTC  #