At one point, nearly five years ago now, I not only used DataGrids…. I liked them. I’ve learned a lot since then, I recall thinking the other day that Microsoft must have had a bit of an off year when they decided to release a web development platform which pretty much relied on the client having Javascript available.
Have you made any claims in the past which you’d like to own up to now? Or do you think any of the current fads of today are going to look foolish in five years time?
http://weblogs.asp.net varies in quality quite a bit, but it’s worth being subscribed just so you always catch ScottGu’s postings. But recently I’ve noticed the Visual WebGui blog. This is effectively a product blog - every post since February is a promo for the Visual WebGui tool. Is this what weblogs.asp.net is about? Should posts like this be a regular feature in the content of this community web site? Is it really in the interest of the community at large? Andrew Stopford also has a blog there, and while he talks about MbUnit a lot, his posts never feel like they were written by a marketing department. He also speaks on quite a range of subjects, so his blog doesn’t leave me with a bad taste in my mouth in the way the Visual WebGui one does.
I guess posters can write whatever they like, but it seems like a waste to turn a good community into an advertising platform.
I wanted to quickly spike an idea that I had last night, and while normally I’d use Monorail, I thought it was high time I took an interest in ASP.NET MVC. It took about ten minutes for me to stumble to a halt.
(more…)
Last week I sat down to create a proof of concept for a Visual Studio-style intellisense implementation written purely in Javascript. I’m quite pleased with the results, although it’s not very robust. Let’s cut to the chase - have a look at the pure javascript intellisense demo, or download an archive.
Now, let me explain what’s happening there before you get too underwhelmed. Basically, when you type, the script runs a tokenizer to split your previous text into chunks. When that tokenizer hits upon a delimiter, in the demo that’s the “.” character, it’ll send your previous token to the server and popup the result in the intellisense box. You can tab to the box and hit enter to select an option. Pressing tab also cycles through the options in the box.
What I’ve written is very simple. The tokenizer can be totally swapped out, so you could define your own rules for parsing your input and obtaining a token. And when the token gets to the server, you can interpret it in any way, returning anything back to be put in the intellisense box.
Like I say, this is proof of concept stuff only but I can definitely see applications for it. It’s been tested in FF3 and IE8 Beta - nothing else. I’ve got an SVN repo online and would happily accept patches or comments. Download Javascript Intellisense here.
Practical Generics: CrudController
June 20th 2008, 6:48 pm in .NET, C#, Development, NHibernate, Patterns, Snippet.
In my last post I discussed code reuse in the form of an abstract CrudController class: a means of providing create, read, update and delete actions for a given entity. In addition, that class provided the ability to work with an entity specification class to allow for filtered reads - which is just another name for search results.
I’m going to show C# code samples for building with a class like this, but you’ll have to fill in the gaps in terms of how you can work with it. The code to list entities is the most interesting and will demonstrate the concept best, so I’m going to focus on that. To begin with, let’s assume a very simple entity:
public class Post
{
public DateTime CreatedOn { get; set; }
public string Headline { get; set; }
public string Body { get; set; }
public string Username { get; set; }
}
So, to begin with we’d like to list Posts. A typical method to do so would be:
public void List()
{
PropertyBag["posts"] = PostRepository.FindAll();
}
But remember that in my case, I’m trying to create a reusable method of doing this, and that I’m also going to be working with ExtJS which is going to consume JSON. So, I have the following class:
public abstract class CrudController<Entity>
{
private IRepository<Entity> _repository;
public void GetJsonList()
{
RenderText(
JsonHelper.Serialize(_repository.FindAll())
);
}
}
public class PostController : CrudController<Post>{}
I need a shell PostController, but most of the action is happening in the CrudController, and I’m using the magic of Windsor and generics to make it happen. By passing Post as a type parameter to CrudController, Windsor will then give me the correct IRepository<T> to work with, and from there it’s a simple matter of fetching the list of Post Entities in the same way I did in the previous code sample. I want to get a JSON string back, so I’m passing that list to a helper to serialize to JSON.
The next step is to make this listing method a bit more flexible and a bit more powerful. I want to do a couple of things - paging, sorting, and searching. Here’s my new method signature for GetListJson:
void GetListJson(int start, int limit, string sort, string dir, EntitySpecification spec)
The arguments “start” and “limit” are for paging, saying which record I should start from and how many I should return. The “sort” argument tells me the column I should sort on, and “dir” gives me the sort direction. But what about EntitySpecification? Let’s show it in context:
public abstract class CrudController<Entity, EntitySpecification> where EntitySpecification : ISpec
{
private IRepository<Entity> _repository;
public void GetJsonList(int start, int limit, string sort, string dir, [DataBind("spec")]EntitySpecification spec)
{
spec.AddOrder(sort, dir);
spec.FindAll(_repository, start, limit);
}
}
public class PostController : CrudController<Post, PostSpecification>{}
As you can see, EntitySpecification is databound by Monorail; incoming parameters are passed to the specification to build up a criteria for querying, as described in Ayende’s search specification post. That means that I don’t have to explicitly handle searching in my CrudController at all, because it’s all handled by the EntitySpecification. A sample PostSpecification could look like this:
public class PostSpecification : ISpec
{
private ICriteria _criteria;
private string _username;
public virtual string Username
{
get { return _username; }
set {
_username = value;
if (value == null)
return;
_criteria.Add(
Expression.Eq("Username", value)
);
}
}
public void AddOrder(string sort, string dir)
{
var order = (dir == "ASC" ? .Order.Asc(sort) : Order.Desc(sort));
_criteria.AddOrder(new Order());
}
public IList<Post> FindAll(IRepository<Post> repo, int start, int limit)
{
repo.Find(_criteria, start, limit);
}
}
When Monorail runs the databinder, the Username property’s getter will be called and the private criteria will be altered. When the specification’s FindAll method is called, that criteria is passed through to filter the returned records.
Let me know if you have any improvements or suggestions, and thank you again to Ayende for the specification ideas.
I’m working with the awesome ExtJS framework again, creating an administrative interface to a huge amount of data. Each screen on this interface is basically a pageable grid with an editor window which pops up if you click a row. The grids can be sorted, and a separate filter area allows you to narrow down the items displayed on the grid in a manner unique to each screen.
The first time I wrote something like this using Monorail and ExtJS, I’d estimate that the javascript code was about 300 lines and the C# was maybe 150. Bear in mind that these screens, while differing due to the data being displayed, were essentially just CRUD interfaces. That means that to create a new screen, I’d be copying and pasting a lot of very similar code.
I’m sure you’ve been in this sitation before. If you’re really only going to be using this code in one or two places, there may be little value in making it a bit more generic. However, as soon as you break past that and find yourself copying and pasting the same code over and over, it’s a sure sign that you need to step back and pull out common functionality. That’ll provide three benefits:
- Less code means less to maintain
- It’s easier to create a new screen (copy/paste is never nice)
- Code reuse means silly errors are more quickly caught
In my situation I first created an abstract CrudController
In the ExtJS side of things, I was able to subclass the GridPanel component and have a component that would automatically have a PagingToolbar, a particular click handler, and other default settings. I was also able to tailor the arguments to reduce the amount of code I needed to write to create it. Here’s a simple example.
this.grid = new App.standardGrid({
cm: new Ext.grid.ColumnModel([{
header: 'Id',
dataIndex: 'Id'
}, {
header: 'Created',
dataIndex: 'CreatedOn',
renderer: function(val) {
return val.format('l d F Y');
}
}]),
fields: [
{name:'Id', type:'int'},
{name:'CreatedOn', type:'date'}
],
url: '/admin/quote/getjsonlist.castle',
edit: this.edit,
scope: this
});
Secondly, I could create a subclassed Ext.Window which would give me a better reusable editor dialog. Here’s how I defined that:
App.window = Ext.extend(Ext.Window, {
height: 500,
width: 500,
modal: true,
resizable: false,
draggable: false,
closable: false,
bodyStyle: 'background: #eee'
});
As you can see, this is just a matter of giving sane defaults for a modal window, but later I subclassed App.window itself to create App.formWindow which was much more powerful.
These three steps dramatically reduced the code required to create a new admin screen in my application. More importantly, I cut the amount of boilerplate code I was copying every time to zero, which meant the code I did have to write was all important stuff. Less wading through identikit javascript means I’m a much happier developer!
I have a relationship which would normally be described as one-to-one. It’s very similar to a Employee / EmployeeDetail relationship which you see used in many examples. My issue is that I’m working with legacy data, so the “child” part of the relationship, the EmployeeDetail, probably won’t exist.
I’m struggling to understand how to map this. I know if it wasn’t for the absent EmployeeDetails, this would be one-to-one. So I’m loathe to think about this in terms of another relationship type because as soon as the EmployeeDetail is available, it will be one-to-one again.
I’d appreciate any thoughts anyone out there might have.
Mirvoda Sergey has announced NHAML for Monorail. Andrew Peters brough NHAML to ASP.NET MVC last year, and now us Monorail users can enjoy using a very different kind of templating engine to the others available for Monorail. Check out this HAML tutorial if you’d like to familiarise yourself. Thanks to Mirvoda Sergey!
I’m banging my head trying to solve a particular type of querying problem. I think I can simplify it like this:
Categories have many Posts, Posts have many Comments
I’d like to search for Comments with a particular author, which is easy enough, but I’d like my result set to be made up of Blogs which contain Posts which contain Comments with author = ‘ramsay’.
The problem I’m having is that if I have 50 Comments then it’ll return 50 duplicate Blogs to contain those comments. Argh! I can add groupings (i.e. group by Blog), but that means it’ll only pull back the things I group by and not the full Blog objects.
Taming Sites with Firefox - UserContent, AdBlock and NoScript
May 9th 2008, 1:04 am in Firefox, Web.
It began with AdBlock… this extension to Firefox automatically removes adverts from the pages you browse - including the most annoying animated Flash horrors. It even updates itself to make sure that it stays one step ahead of ad-serving sites.
Unfortunately there were a couple of persistant sites that remained troublesome to visit. One of those was Football365, which used Javascript to include a couple of diversions, including a speedy tickertape (and we all know how annoying those can be). In stepped NoScript, which allows you to set up a whitelist of sites which should be allowed to run scripts. Bye bye ticker tape!
So now I had a calm and much less cluttered Football365. I remember a Firefox feature which would let me take it a step further. A custom UserContent.css allows you to write a CSS targetted to specific domains, meaning you can completely override the styling of a given website. For F365 I removed a couple of blocks I wasn’t interested in or that cluttered things up, made the layout full width, and increased the font size a little, as well as a few other little tidying tweaks.
From an fixed-width animated monster with sound-effect ridden adverts, I’ve now got a sane and readable site which doesn’t torment me with its layout, and in just three simple steps. The most dramatic of these is possible due to the use of a CSS layout underlying the F365 pages, a handy piece of foresight by their web team.