Happy New Year!
Just a really short post from me, on the last day of the year.
2011 has been a really great year for me. I've been busy starting and working on a bunch of new projects, some open source, some not, but common for all is that I have volunteered my time, free of charge, to the good idea! I still hope that I can make a living having all this fun one day, but for now I just enjoy working with brilliant people and working on brilliant ideas. This is something I hope to do even more in 2012.
The biggest project of 2011 for me has of course been starting and working on MVC Forum, and that is certainly something I'll continue doing in the years to come. Hopefully with the release of version 1 in the first half of 2012, several people will join me and help make MVC Forum the best forum solution for ASP.NET MVC.
Nothing more from me, Happy New Year! Take care!
Categories: MVC Forum - Personal
Posted by Steen F. Tøttrup on 31 December 2011 16:22. There are 0 comments.
MVC Forum should be database independent, but...
Right from the start it has been the plan to keep MVC Forum database independent. This should be possible without too much work with the data provider model we have in place. At least that was the plan.
Another focus area of mine, is globalization and localization, part of this is to make MVC Forum able to correctly handle timezones. The forum owner can select the default timezone of the forum, and the users can select which timezone suits them best. And of course this should all be handled correctly.
So this is where the problem is. If you use a regular DateTime property with Entity Framework, you get a DateTime column (with MS SQL server). This datatype does not store the timezone. Well, that shouldn't really be a problem I figured. Whenever we use dates in MVC Forum, we'll just make sure they are always in UTC, that way we only have to do something special when the dates are shown in the UI. Good plan, but then Entity Framework enters the mix!
When Entity Framework populates the properties on the POCOs with data from the database, it will set the DateTimeKind on all datetimes to unspecified. Seriously? No way around this? I haven't been able to find any. I was hoping for some way of getting to work with the datetime values, before they are assigned to the properties, but no!? No convention to handle this? No configuration? No nothing!?
A quick, and unfortunately dirty, way around this is that with version 0.8 we're using DateTimeOffset instead of DateTime for the properties on the POCOs. This makes things a bit complex. Most people are used to working with DateTime, and have no idea what DateTimeOffset is etc. Even worst, to store this property in the database, Entity Framework will create a DateTimeOffset column, which only exists in MS SQL 2008 and later. So now all of a sudden MVC Forum is a "one-database-product". I really hate that!
If you know of any way around this? A better way of handling it, or... Please let me know! We're probably releasing version 0.8 with this "defect", but we're certainly not going to release version 1.0 with a dependency on MS SQL 2008+. I'm sure I can work around this issue in a nHibernate data provider, but we're not going to throw away the Entity Framework provider!
Categories: MVC Forum - Entity Framework - DateTime - DateTimeOffset - MS SQL 2008
Posted by Steen F. Tøttrup on 29 December 2011 22:33. There are 0 comments.
Integrating MVC Forum with existing solution!
It has always been my plan to make sure MVC Forum could easily be integrated with existing solutions. One of the main tasks for an easy integration would be to let MVC Forum work with any ASP.NET membership provider. This does seem like a bit of a task, as the membership provider framework doesn't provider any event hooks, and MVC Forum needs to know when an user is created etc. So how should this be handled, without forcing anybody to do a lot of custom code to their existing solution (which might be closed source software etc.)?
My idea to solving this problem is to write a custom membership provider that could wrap any existing provider. All this wrapper should do, is call the actual membership provider and when needed, tell MVC Forum about the changes (new user created, existing user deleted, user updated etc.).
So let me give you an example of what to expect when we release MVC Forum next time. Your web.config file could look a bit like this:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <membership defaultProvider="SqlProvider"> <providers> <clear /> <add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SqlServices" applicationName="MyApplication" ..... /> </providers> </membership> </system.web> </configuration>
And you really don't want to use another membership provider, but you really want to add MVC Forum to your web site. So with the next release of MVC Forum, your web.config file will look like this:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <membership defaultProvider="ProviderWrapper"> <providers> <clear /> <add name="ProviderWrapper" type="mvcForum.Web.Providers.MembershipProviderWrapper" WrappedProvider="SqlProvider" /> <add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SqlServices" applicationName="MyApplication" ..... /> </providers> </membership> </system.web> </configuration>
Can you spot the magic? Probably not, because there's no magic! Whenever any methods are called on the default membership provider (the ProviderWrapper) the calls will be redirected to the wrapped provider (the SqlProvider). Let's look at some code:
public class MembershipProviderWrapper : MembershipProvider {
private string wrappedProvider;
public override void Initialize(string name, NameValueCollection config) {
base.Initialize(name, config);
if (String.IsNullOrWhiteSpace(config["WrappedProvider"]))
throw new ArgumentNullException("WrappedProvider");
this.wrappedProvider = config["WrappedProvider"];
}
protected MembershipProvider ActualProvider {
get { return Membership.Providers[wrappedProvider]; }
}
public override Boolean ValidateUser(string username, string password) {
// Let's call the wrapped provider!
bool loggedOn = this.ActualProvider.ValidateUser(username, password);
// Did we succeed?
if (loggedOn) {
// Let's get the membership user!
MembershipUser user = this.GetUser(username, false);
// And the matching forum user.
ForumUser u = this.UserRepository.ReadOne(new ForumUserSpecifications.SpecificProviderUserKey(user.ProviderUserKey.ToString()));
// Let's update the last known IP
u.LastIP = HttpContext.Current.Request.UserHostAddress;
// And the last visit datestamp.
u.LastVisit = DateTime.UtcNow;
// Commit the changes!
this.UnitOfWork.Commit();
}
return loggedOn;
}
}
We could probably live without the last known IP address and the last visit timestamp, but it would take a lot of (ugly) work-arounds to not know when a new user was created, or when an user is deleted etc.
If you disagree with the way we've solved this issue and you have all the right reasons, you can still make me change my mind, just give me some feedback!
Categories: MVC Forum - Alpha 4 - Membership Provider
Posted by Steen F. Tøttrup on 06 December 2011 07:38. There are 2 comments.
The third alpha is out!
I'm so sorry! In my last post I promised that I would post some more code, and that's more than 14 days ago. And even worst, I'm not going to post any code!
I just wanted to let you all know that I've just dropped MVC Forum version 0.7 (alpha 3) off on Codeplex, so go grap it, and give me some feedback, please!
It's been hard work, and some annoying errors put me back 14 days. The upside is that MVC Forum has never been better tested, and now I have the setup for building even more tests. So far I have put in 27 tests.
So what's next? I think I'll take another look at how MVC Forum can be integrated with existing solutions, so I'll probably change the way the Membership provider works, but... more on that soon.
Categories: MVC Forum - Alpha 3 - Alpha 4
Posted by Steen F. Tøttrup on 02 December 2011 21:58. There are 0 comments.
Testing, or when your application gets complex!
There's really no good reason for not starting to write tests right from the start of any project you work on. Some people like the test driven development way of doing things, some don't. Hopefully most developers have come to the conclusion that when writing software, you really need to test your work. Most of my work start out as some sort of hobby project or POC, so most of the time I don't start writing tests from day 1. Of course I should, but I like being honest, so honestly: I don't!
In the first couple of months of working with the MVC Forum project, it hasn't been that hard testing the software, but even so, version 0.6 was released with a stupid error in the Forum Admin area that means you can't edit an user! Stupid! I should have caught that. I put my focus into testing that users could sign up, create topics, post replies and that is about it. The Forum Admin area hasn't been tested at all.
What happens is that somewhere along the way your project crosses a boundary where it gets too complex to totally understand the impact of the changes you make. If you sat down and considered each and every change, you would probably know exactly what would break, but you have to make progress and really don't have the time. And why would you want to do that anyway, when you could use the time adding code and features to your project? Which is what really matters to the users. Or maybe not! I bet they would prefer less features in a well-tested solution to large amounts of untested features.
MVC Forum has crossed that boundary months ago, and with the up-coming version 0.7, we're seriously past the point of no return. With the anti-spam measures and search indexing, the amount of senarios you have to work your way through to test each and every pitfall, would take days (and a very long list with the senarios, so you don't forget one!).
So I've come to the conclusion that it's time to start testing the UI, and for that I'm going to use NUnit (for executing the tests) and Selenium (the web drivers, for interacting with MVC Forum through a browser). Yes, this will take time away from putting more code and features into the MVC Forum project, but at least it still involves code! And the added benefit is that it will most likely catch some errors, and might even make me think about how different features work or should work. Of course this testing is done automatically, use the NUnit test runner or the Visual NUnit Visual Studio add-on for this. Once you've written a test, that test is valid until you change the way the tested feature works, so over time the amount of tests and areas tested, will just grow and grow. Who knows, we might get close to the magic 100% test coverage one day.
Yes, this ended up as a no-code post, I'm sorry! I promise I'll post some code next time. About next time, hopefully MVC Forum version 0.7 (Alpha 3) is released in a few days, so hopefully I'll be back with some info on the theme of the next release (being version 0.8).
Categories: MVC Forum - NUnit - Selenium
Posted by Steen F. Tøttrup on 16 November 2011 06:54. There are 0 comments.
