Welcome to EMC Consulting Blogs Sign in | Join | Help

Anthony Steele's Blog

  • Three aspects of your first Silverlight project.

    I have been working on a Silverlight project, and the experience of using it for a period of several weeks on a real application has been quite good. I thought I would highlight three aspects that made it good.

    1: It has real C# and .Net inside.

    The CLR used in Silverlight may be cut-down, but the developer experience isn't. We used Visual Studio 2008, ReSharper, and all the good parts of C# 3.5:  generics, extension methods, Lambda expressions and LINQ.

    There is no LINQ to SQL or EF or database drivers -all data from servers comes over web services, but there is LINQ to objects and to XML.
    There are even third party add-ins. We used the NInject IOC container. Other IOC containers like Unity also support Silverlight now. There are also Extensions and testing tools, and mocking frameworks are getting there.

    The code-run-fix cycle in Silverlight is very quick, giving immediate feedback on what your code changes have actually accomplished. I think we produced that application faster than a similar website could have been done.

    2: XAML

    XAML is the UI mark-up language used in Silverlight. It's also used in WPF, which is Silverlight's older brother and the successor to Windows Forms.

    It's very good: all .Net coders should know the basics to XAML, unless you want to only ever work in ASP.Net. I'll rave about XAML at length given the chance, despite only being a novice. Despite its power and depth, the basics are easy to grasp. Simple Windows Forms style interfaces are easy in XAML, and it will give you room to do much more if you need to. The look and feel of the application can be set or changed in styles, and the data binding support is so good that it generally becomes a key part of a Silverlight or WPF application.


    XAML encourages a separation between functionality and visual style, so that parts of the application can be handed back and forth between designer and developer as needed.

    Compared to a web app where cross-browser issues are common, a Silverlight application looks the same between browsers, and even on an Apple Mac. The cross-browser issues that we had were few, and generally around integrating with the browser, or the machine's installed fonts. Compared to a desktop application, the installation is basically non-existent and the security implications lesser.

    3: Developers

    There is a perception that Microsoft's strategy in "taking on Flash" is to leverage the popularity of C# and get an army of low-level C# developers doing Silverlight. That perception is false in at least one respect - the Silverlight developers that I worked with were not low-level. Take a look at the ViewModel pattern that served us well.


    I'm sure that you can do "put the data access code in the button-click handler" development in Silverlight if you wanted to, but the environment is rich enough to allow a lot of other ways of working that are more appropriate for larger applications.

     

    .. and also Silverlight 3, which is now in beta, is building on these strengths.

     

  • Social web beyond walled gardens

    Blogging was technically possible in the early 1990s, but only gained ground when people realised how to do it in the last 1990s and settled on the basic features - entries are shown in reverse chronological order, with comments on entries, Syndication using RSS or ATOM. It's a medium with low barriers to entry - there are a large number of blog engines, open source and not, hosted or for a variety of platforms; and largely they work in similar ways.  To the point where is has been said that "Blogging apps are the new Hello World".

    I'm a fan of the social web, which adds a lot more than basic blogging. But the social web that most people know operates in walled gardens, on FaceBook, Orkut, LiveJournal, Twitter or the like offering extra features at the cost of locking you into only using them when interacting with other users of the same site. I don't think that it necessarily has to be that way. Blog engines just have to interoperate a bit more richly to enter the same space and open it out into a game where anyone can play.

    OpenId I had hoped would be the key to authenticating users whose home is elsewhere. OpenId has not yet taken the world by storm, but the basic idea is sound, so I hope that they keep refining and promoting their idea so that a later version or derivative catches on, and that it's not called "facebook connect" -  Punting the whole thing into one of the walled gardens is not a great idea.

    Here are some ideas to push blogs in a direction that favours a completely distributed approach to social webworking:

    1)      Be an OpenId consumer to support the "casual but identified commenter" scenario.

    2)      Be anOpenId provider so that the blog engine can be a source of identity.

    3)      Support machine-readable data about the blog user, including friends' lists. A standard for this is FOAF.

    4)      Support feeding content to friends only. This last step has no fixed standard yet, but it the key value-added service that the social networking walled gardens provide.

  • Positive support experience with twitter

    A few days ago, I vented my frustration with some ... complex and unintuitive software behaviour  by saying on twitter: "TFS, why do you fail to *undo* a checkout due to your bogus unspecified supposed locked files? I can has SVNburger?"
    I did work around the problem within a few hours, but not before I got this unexpected reply:

    JasonBarile said Can you send me more details on your TFS undo question? I guess that he found this is due to monitoring usage of the phrase "TFS" on twitter.
    JasonBarile is, according to his blog at http://blogs.msdn.com/jasonba/  "a Principal Test Manager for Visual Studio Team Foundation Server at Microsoft"

    So I did send him details, and a few tweets and emails later he had replicated the issue and was offering to send me a hotfix when it was available. (I don't think I need it, we've fixed the issue at hand.)

    Now if, like many people, you've been wondering if twitter is more than just a fun toy, here is an answer. This is an example of using twitter well; how, by caring about the product that you're making and by keeping an eye on your users' chatter, you can produce an unexpectedly good user experience.

    The other lesson is that you're not just talking to your subscribers. The latest generation of communications tools builds in searchability and watchability.

  • C#3 anonymous types as parameters

    Over the holidays, for some light holiday reading while resting the bruises from ski-slope related activities, I took Bill Wagner's book "More effective C#" it showed a few ways in which C#3's anonymous types can be passed to methods, which i had thought was beyond thier scope.

     Given this definition:

    var anonTypedObject = new { Name = "Fred", Balance = 12 };

    All we can say about it is that it's descended from Object, so it can be passed to a method ike this:

    static void ShowTypeOfObject(Object obj)
    {
      
    Console.WriteLine("(O) Type is " + obj.GetType().ToString() + " value is " + obj.ToString());
    }

     ShowTypeOfObject(anonTypedObject) produces output of:

    (O) Type is <>f__AnonymousType0`2[System.String,System.Int32] value is { Name = Fred, Balance = 12 }
     

    This also shows that that the generated anonymous type is itself a kind of generic tuple.

     However strongly-typed methods can also accept the anonymous type, if the method is generic. This version works much the same:

    static void ShowTypeGeneric<T>(T t)
    {
       
    Console.WriteLine("(G) Type is " + t.GetType().ToString() + " value is " + t.ToString());
    }

    ShowTypeGeneric(anonTypedObject); 

    But what useful work can a generic method do on an anonymous type? The generic method has to make sense for any type from object on down, so it knows little useful about the type. But it can also be passed a function to apply to the data, which does know what to do with the anonymous type. If it's an anonymous function, of course. In a more complex example the generic method might check nulls or iterate a list as well as applying the worker method, but here's a very simple example:

    static void ShowFuncOutput<T>(Func<T, string> func, T data)
    {
       
    Console.WriteLine(func(data));
    }

    ShowFuncOutput(v => "Lambda: Value is " + v.ToString(), anonTypedObject);

     Which produces output as you might expect;

    Lambda: Value is { Name = Fred, Balance = 12 }

    Though if it gets much more complex than this, I would recommend paying the cost of a non-anonymous type, it's likely to be worth it in the long run.

  • Adding OpenId to Oxite, Part 2

    (Part 1 is here)

    The main part of the Openid support is in the controllers and in the view. Fortunately the heavy lifting has been done already, with a library called DotNetOpenId and sample code that started life in Rob Connery's storefront sample, and was worked on by my colleagues Howard Van Rooijen and Pete Worthington before I got hold of it.

    First, install the DotNetOpenId library and reference it from the Oxite.MVC project

    Add an action called OpenIdSignIn to AccountController:

            public ActionResult OpenIdSignIn()

            {

                var openid = new OpenIdRelyingParty();

     

                if (openid.Response == null)

                {

                    string claimedUrl = Request["openid.claimed_id"];

     

                    // Stage 2: user submitting Identifier

                    Identifier id;

                    if (Identifier.TryParse(claimedUrl, out id))

                    {

                        IAuthenticationRequest request = openid.CreateRequest(claimedUrl);

     

                        // email and display name would be nice, but we can do without it

                        ClaimsRequest claimsRequest = new ClaimsRequest

                            {

                                Email = DemandLevel.Request,

                                Nickname = DemandLevel.Request

                            };

                        request.AddExtension(claimsRequest);

     

                        request.RedirectToProvider();

                    }

                    else

                    {

                        ModelState.AddModelError("_FORM", "Invalid identifier");

                        return View("SignIn");

                    }

                }

                else

                {

                    // Stage 3: OpenID Provider sending assertion response

                    switch (openid.Response.Status)

                    {

                        case AuthenticationStatus.Authenticated:

                            {

                                ClaimsResponse claimsResponse = openid.Response.GetExtension<ClaimsResponse>();

     

                                string nickname;

                                string email;

                                // did we get a claims response?

                                if (claimsResponse == null)

                                {

                                    nickname = openid.Response.ClaimedIdentifier.ToString();

                                    email = string.Empty;

                                }

                                else

                                {

                                    nickname = claimsResponse.Nickname;

                                    email = claimsResponse.Email;

                                }

     

                                LogOpenIdLogin(openid.Response.ClaimedIdentifier, nickname, email);

                                return RedirectToRoute("Home");

                            }

                        case AuthenticationStatus.Canceled:

                            ModelState.AddModelError("_FORM", "Canceled at provider");

                            return View("SignIn");

     

                        case AuthenticationStatus.Failed:

                            ModelState.AddModelError("_FORM", openid.Response.Exception.Message);

                            return View("SignIn");

                    }

                }

                return new EmptyResult();

            }

     

            private void LogOpenIdLogin(Identifier claimedIdentifier, string nickname, string email)

            {

                // if the user record does not exist, create it

                string userName = claimedIdentifier.ToString();

                IUser user = MembershipRepository.GetUser(userName);

     

                if (user == null)

                {

                    Guid defaultLanguageID = LanguageRepository.GetLanguage(Config.Site.LanguageDefault).ID;

     

                    MembershipRepository.AddOpenIdUser(userName, nickname, email, defaultLanguageID);

                }

     

                FormsAuth.SetAuthCookie(userName, false);

            }

     

    And in the SignIn.aspx view add a form for the OpenId to be entered:

                 <div id="openid">

                    <h2>Use Your Open ID</h2>

                    <div id="spacer"></div>

                    <form method="post" action="<% =Url.Action("OpenIdSignIn") %>" class="login">

                  

                    <!-- BEGIN ID SELECTOR -->

                    <input type="text" class="openidinput" size="40" id="openid.claimed_id" name="openid.claimed_id" />

                    <script type="text/javascript" >

                        idselector_input_id = "openid.claimed_id";

                    </script>

                    <script type="text/javascript" id="__openidselector" src="https://www.idselector.com/selector/9ef50c2962fc7066564dc829214efbe0ef945335" charset="utf-8"></script>

                    <!-- END ID SELECTOR -->

                    <input type="submit" value="<%= Localize("Login") %>" class="submit button" />

                    <br />

                    </form>

                    <div class="hint">

                        Open ID is an identity system that allows you to sign in to websites with a single account.

                        Your username and password are secure with Open ID - and you don't have to remember yet another password.

                    </div>

                </div>

     

    And that's all.

    We are using a nice bit of Javascript Ui from IdSelector.com which, as you can see, has a serial number in it. Unfortunately they've stopped issuing these. I hope a good replacement comes along.

    There’s lots more that can be done with OpenId here. For instance, the OpenId login form would be useful on the comments page - OpenId users are more likely to be just casual commenters, whereas the people writing the blog could take the time to make a local login. The users created via OpenId do not have any permissions, so they can add comments but not post; which is a sensible default.

    I have more than one OpenId, so it would be nice to group them together into my account. Oxite is not yet an OpenId provider, which would be interesting.

    A mature system would be able to block open ids based on patterns in the url, allowing or disallowing providers based on security considerations. But Oxite first should gain ability to list users, and change their permissions – e.g. admin, editor, contributor or locked out, and track the user's time and IP of the last login, etc

    I’m sure that I made mistakes in this implementation – there’s lots that I don’t know about MVC and about OpenId.

  • Adding OpenId to Oxite, part 1

    I am following up on my last post on Oxite by showing how to add OpenId login support to it. I won't finish this today. This first one will cover the repository changes needed.

    First, download the Oxite source and set up the database. From a database perspective, the table where user logins are stored is called oxite_user. In code this is referenced via the IUser interface.

    In general, I would like to use the OpenId "claimed identifier" as the user name. User names have to be unique, so this the user name “http://AnthonySteele.myopenid.com/” is used up by my OpenID login, but I think we can live with that. We can tell OpenId logins from regular ones by eye (OpenId logins look like Urls), but I'd like a flag to do it unambiguously.

    In the code this flag is an enumeration:

    namespace Oxite.Data

    {

        /// <summary>

        /// How does the user log in

        /// </summary>

        public enum UserLoginMethod: byte

        {

            /// <summary>

            /// Default/unknown value

            /// </summary>

            Unknown = 0,

     

            /// <summary>

            /// The user has a local user name and password

            /// </summary>

            LocalLogin = 1,

     

            /// <summary>

            /// The user logs in using an openId from a different site

            /// </summary>

            OpenId = 2

        }

    }

     

    There could be Cardspace or some other kind of login later. the flag needs to be stored on the user data in the database, with all existing logins marked as “local login”. In SQL, execute:

    alter table oxite_user

    add UserLoginMethod tinyint not null default 1;


    Add the login method to the IUser interface:

        public interface IUser

        {

    ... as before...

     

            UserLoginMethod LoginMethod { get; set; }

    Then fix the fake implementation of IUser with an auto property:

        public class FakeUser : IUser

        {

            #region IUser Members

    ... as before...

     

            public UserLoginMethod LoginMethod { get; set; }

     

    Then do some drag and drop to regenerate the LINQ data classes, which will give the database-backed User class a property UserLoginMethod, of type short. Now we want the strongly-typed wrapper:

     

        partial class oxite_User : IUser

        {

            #region IUser Members

     

            ... as before ...

     

     

            public UserLoginMethod LoginMethod

            {

                get

                {

                    return (UserLoginMethod)UserLoginMethod;

                }

                set

                {

                    UserLoginMethod = (byte)value;

                }

            }

     

    The Oxite membership repository does not yet have a way to add users, so we need to add one:

     

        public interface IMembershipRepository

        {

            ... as before ...

     

            /// <summary>

            /// Add a new user with an OpenId login

            /// </summary>

            /// <param name="userName">The claimed identifier</param>

            /// <param name="displayName">the name to use onscreen</param>

            /// <param name="email"></param>

            /// <param name="defaultLanguageId"></param>

            /// <returns></returns>

            IUser AddOpenIdUser(string userName, string displayName, string email, Guid defaultLanguageId);

     

    This is implemented in the fake repository as follows:

            public IUser AddOpenIdUser(string userName, string displayName, string email, Guid defaultLanguageId)

            {

                FakeUser newUser = new FakeUser();

                newUser.ID = Guid.NewGuid();

     

                newUser.Username = userName;

                newUser.DisplayName = displayName;

                newUser.Email = email;

     

                newUser.LoginMethod = UserLoginMethod.OpenId;

     

                Users.Add(newUser);

     

                return newUser;

            }

    And in the Linq to SQL repository as follows. This isn't perfect (particularly the choice of salt should be unique to the user, and it's not clear how the email should be hashed), but it will do until more complete user-adding code is in place in Oxite.

            public IUser AddOpenIdUser(string userName, string displayName, string email, Guid defaultLanguageId)

            {

                oxite_User newUser = new oxite_User();

                newUser.ID = Guid.NewGuid();

                newUser.Username = userName;

                newUser.DisplayName = displayName;

     

                newUser.Email = email;

                newUser.PasswordSalt = "NaCl";

     

                newUser.Password = saltAndHash(userName, newUser.PasswordSalt);

                newUser.HashedEmail = saltAndHash(email, newUser.PasswordSalt);

     

                newUser.LoginMethod = UserLoginMethod.OpenId;

                newUser.DefaultLanguageID = defaultLanguageId;

                newUser.Status = 1;

     

                dataContext.oxite_Users.InsertOnSubmit(newUser);

                dataContext.SubmitChanges();

     

                return newUser;

            }

     

    So that’s the repositories and domain objects.  Next: the controller and view code to make OpenId logins possible.

  • Oxite

    Today I am looking at  Oxite. Not this Oxite, but this Oxite. It’s a sample application on the ASP.NET MVC platform. It’s a blog engine, so it’s doubly interesting to me. New MVC blogging engines crop up on CodePlex every month or so (and I have contributed code to BlogSvc). Generally they pass without much (or any) notice.

     

    Oxite, however, arrived with an impressive degree of completeness, and generated a lot of publicity. Not all of it was accurate – some seemed to think it was a major new part of Microsoft’s internet strategy rather than a sample app by a couple of guys at Microsoft. As it stands, it's not a competitor to WordPress. I like WordPress, I have deployed and configured it and several times. While I'd like something like that which I can also hack in C#, Oxite is not there. Yet.

     

    Code reviews followed. See Rob Connery's blog, here and here for details. Oxite is clearly not ready for general use as finished software, it’s not even ready as a best-of breed code sample, but developers may be interested. Oxite has a few code issues (see Rob Connery’s links above), but it's also got advantages:

     

    Advantage 1: The guys who wrote it have put a lot of time and work into it - they can afford to, it's part of their day job.

     

    Advantage 2: Oxite got instant publicity and community, including a code review from Rob Connery, and lots of other people poking at it- orders of magnitude more downloads and comments than the other MVC blog engines on codeplex got, combined.

     

    I'm watching Oxite with interest - I want to know if they will take the advice on board, and will it become more than just a "sample app".

     

    Next time I will show putting OpenId support into Oxite, with help from DotNetOpenId and sample code from Rob Connery via a few of my colleagues.

     

     

     

  • Extension methods for generic lists

    A while back (has it been two years already?) I wrote about using the new generics feature in C# to make strongly typed lists, and subclassing generic lists as a way of making lists that are both strongly typed and have  type-specific methods attached, and doing it  with the bare minimum of coding effort.

    This technique is not widely used, for better or worse.  Today I'd like to look at a few ways that this would differ if done in C# 3.5 using extension methods.

     

     In an extension method, "this" can be null.  

     The code someObject.operation(); will normally produce a null reference exception right away if someObject is null.  But not in an extension method. This quirk is used to great effect in the null-test extension method posted on Stackoverflow:

    public static class Extensions
    {
            public static void ThrowIfArgumentIsNull<T>(this T obj, string parameterName) where T : class
            {
                    if (obj == null)

                      throw new ArgumentNullException(parameterName + " not allowed to be null");
            }
    }

     

    You have more choice as to which type to attach an extension method 

    Rather than write public static int Sum(this List<int>items), you can also type items as one of the  interface types that List<int> supports - as IList<int> or IEnumerable<int>. In general, you should use the weakest type that it is sensible to attach the operation to, so as to make the operation usable in the widest circumstances. A method typed as  public static int Sum(this IEnumerable<int>items) can also be used on arrays of ints, for instance. This makes it more flexible.

     

    Extension methods are separate

     Extension methods do not necessarily travel with the class that they work on. They are declared in separate class, and potentially separate namespaces and assemblies. I have mentioned this before, but it raises the design possibility that appropriate extension methods could be used to make objects gain different functionality in data and display layers parts of an application, without causing dependencies to be placed in the object itself.


     

    The extension method model offers new, simple and very flexible ways of working with strongly-typed collections of objects.

     

  • The ASP.NET MVC beta is out

    The ASP.NET Model-View-Controller kit has finally gone into beta. Blog posts from Scott Guthrie, Scott Hanselman and Phil Haack give more details.

    The five preview releases that have preceded it were well received, and the Beta finally brings this exploratory and community design feedback phase to a close, so that there should be few changes between the beta and the final release. Scott Guthrie summarised the project's progress as "not 100% feature complete, we think the major subsystems are all getting really close to being done, and that the quality level is now pretty good".

    The MVC kit is an interesting addition to the ASP.NET framework, and is a good alternative to the ASP.NET Webforms.

    But the big question is, is it ready? Can you develop a site against this beta?

    Yes, it comes with a go-live licence.

    But should you?

    I think so. www.stackoverflow.com is live and facing the internet right now, and is built on it. Jeffrey Palermo is doing "several enterprise client applications" on it.

    If you like TDD, simple URLs, and the web way of working rather than ASP.NET WebForms' stateful model, URL routing and other Ruby on Rails-inspired goodness, then the advantages of the MVC kit should outweigh the remaining bugs.

    It's going to be an important part of ASP.NET 4.0, so it's well worth getting to know. It's the first Microsoft download to come with jQuery. and apparently, chicks dig it.

     

  • Architecture with layers, active records, and onions

    In the 1990s I coded on a few systems where the architecture was that we attached database functionality to our business objects, so you could do something like

     

      someObject.Value = 4;

      someObject.Save();

     

    While this looks appealing, this pattern (I later learned that it is called active record) has fallen out of favour, in favour of a model where the database code is contained not in each object, but in a layer that deals with database and nothing else, e.g:

     

    someObject.Value = 4;

    dataLayer.Save(someObject);

     

    Now the data layer depends upon the object model, and not vice versa. Database code is grouped together, and is easier to change or replace. These days it's often services as well as databases that data comes from and goes to.

     

    We have the "layered" application as the default mainstream pattern. However there have been new ideas percolating. Inversion of control gives us tools to manage and rearange these layers.

     

    I read Jeffrey Palermo's Onion Architecture and found myself nodding in agreement. I don't really mind how much it resembles Hexagonal, it's good either way.

     

    This is a workable, flexible  model, where the object model is made from Plain Old Objects with no special attributes, interfaces or base classes, and knows nothing about any persistence, service or UI layers.

     

    I have also been watching  Rob Conery's ASP.net MVC storefront demo video series. It's excellent. Despite supposedly being about the asp.net MVC kit, it shows a lot of good things about a LINQ to SQL data layer, IOC, mocking and testability. And the pattern is much like the onion. (These videos may no longer be on the asp.net MVC site. You can find them at http://blog.wekeroad.com/mvc-storefront/ )

     

    But the problem with LINQ to SQL in the default configuration is that the object model is not central, it is in the LINQ data layer.


    There are two ways around this,

     

    First, make LINQ to SQL worth differently, to instead make LINQ to SQL use the object model rather than its own objects. Ian Cooper shows how to do this in his series.

     

    Secondly, you can use the objects generated by LINQ to SQL as data transfer objects only, and copies data from them into the object model. Rob Connery takes this approach and it is surprisingly painless.

     

    In part 10, Rob Connery does something surprising to me - he makes the Shopping cart object aware of the repository interface, so that it can save dependant data. It is given a repository interface on creation, in a Dependency Injection pattern.

     

    This is interesting, this object is using the active record pattern? And if so, is it a bad thing? The coupling that made this a bad idea originally is not present.

     

    To my mind this arangment is not ideal. It may be better to push this code out one layer and attach it to the domain object with extension methods. Extension methods in general give an interesting new possibility - that the object itself is just a data container, but with the right extensions in play it knows how to save itself, or display itself, or whatever the current layer requires.

This Blog

Syndication

Powered by Community Server (Personal Edition), by Telligent Systems