posts - 53, comments - 155, trackbacks - 4

My Links

Archives

Post Categories

Projects

Web Dev

Sunday, June 07, 2009

Undo Within Selected

Today I was working on some code, nothing particularly different than any other day. I did something I have done thousands of times before, made some changes, and then needed to get previous code back. This was quickly done with undo several times, copy to clip board, redo several more and then paste. Then it hit me, why don't we have an undo within selected text? We have a search and replace within selection. Undo within selection complements the search and replace really well, and further, allows for quicker retrieval of code several edits ago. Particularly when the change was a single iteration ago in a particular location… In a sense spatial undo versus temporal undo.

Hopefully this will make it into Visual Studio some day, either as a power tool or third party plug-in.

posted @ Sunday, June 07, 2009 12:53 PM | Feedback (2) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Wednesday, March 18, 2009

ASP NET MVC Version 1 Released

Version 1 of ASP.NET MVC has been released, presumably for MIX in Vegas. It's been a year following the project, and it's exciting to see MVC released after three years of development since March 16th 2007.

http://www.microsoft.com/downloads/details.aspx?FamilyID=53289097-73ce-43bf-b6a6-35e00103cb4b&displaylang=en

Overview

ASP.NET MVC 1.0 provides a new Model-View-Controller (MVC) framework on top of the existing ASP.NET 3.5 runtime. This means that developers can take advantage of the MVC design patterns to create their Web Applications which includes the ability to achieve and maintain a clear separation of concerns (the UI or view from the business and application logic and backend data), as well as facilitate test driven development (TDD). The ASP.NET MVC framework defines a specific pattern to the Web Application folder structure and provides a controller base-class to handle and process requests for "actions". Developers can take advantage of the specific Visual Studio 2008 MVC templates within this release to create their Web applications, which includes the ability to select a specific Unit Test structure to accompany their Web Application development.

The MVC framework is fully extensible at all points, allowing developers to create sophisticated structures that meet their needs, including for example Dependency Injection (DI) techniques, new view rendering engines or specialized controllers.

As the ASP.NET MVC framework is built on ASP.NET 3.5, developers can take advantage of many existing ASP.NET 3.5 features, such as localization, authorization, Profile etc.n

 

 

posted @ Wednesday, March 18, 2009 9:21 AM | Feedback (1) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Friday, February 13, 2009

SmartPen by LiveScribe

Few gadgets actually change my life. I have used PDAs in the past, but they were eventually neglected and never replaced. I have owned a Tablet PC, which ended up being used just like a laptop; so much so, I replaced it with a laptop later. I finally bought an iPod just this year, but it too it seems is going to be neglected and unused. The SmartPen by LiveScribe is different.

 

The SmartPen is aptly named, for it can be used just like a pen with additional features. The features are quite extensive, from the expected digitizing of written material to on paper translation and piano keyboards. While the later features are more for show, there are several features which have completely changed how I do things at work and school.

  • Audio Recording: The audio is recorded and 'linked' to the written material. At a latter point the audio linked to the writing can be played by 'double clicking' the content. Great for reviewing meetings and class notes.
  • Computer Synchronization: The content of the pen synchronizes with the computer by USB with a handy magnetically assisted cradle. The benefit is that the application can search your writing for phrases rather accurately. This is invaluable when doing open note assignments and tests. Some other benefits with the program are the ability to export pages as images and share the notes online through their hosted services.
  • Math: The pen does an excellent job at recording notes containing math. This is an area where the tablet PC seriously struggled.

There are a few nuances as is the case with perhaps every gadget.

  • Ink: I go through an ink cartridge every two and half weeks by just taking notes in courses (15 hours). The ink is not terribly expensive however.
  • Printing Custom Sheets: The program crashes when printing your own 'special' paper. To work around this I had to manually grab the PostScript files from the app and use an open source PostScript printing application. This problem was repeatable across other machines.
  • Deleting Pages: This was a surprise… You can't delete pages. You can delete a whole notebook though… So be careful what you write (Or what others write when testing it thinking they are funny… thanks Sean).
  • Exporting Content: There are two ways to share notes. One is to 'copy' the page as an image, but of course the audio is lost. The notes with the audio can be published, but only through the LiveScribe service. I would like to host the notes myself.

While using the pen, a few ideas have sprung to mind which I would really like to see in the next revision.

  • Dot Matrix Overlay: It would be great to be able to print documents through a LiveScribe service that simultaneously overlaid the print request with the dot matrix, and imported the template into the application. This way the pen could be used in drafting say reports. It should be technically feasible as PrimoPDF demonstrates.

posted @ Friday, February 13, 2009 9:54 PM | Feedback (6) |

kick it on DotNetKicks.com

Sunday, January 11, 2009

Unifico Load Tested with and without WCF Remoting

This is rather exciting to me; I just ran a few load tests on Unifico with and without remoting the services with WCF bindings. I knew the application could remote. The concern was how efficient. I created a quick web test that simply goes through the admin, lists the admin lists, performs a filter, edits and saves an item, then logs out. Roughly every action was hit (eh, it's a spike :)). I then setup the bindings and ran a load test remotely and locally (remotely being hosted on 127.0.0.1).

I like to call the operating point at about 75% cpu. This placed the local run at 282 req/s and the remote run at 214 req/s for a 75% efficiency in serializing all the service requests through WCF. It's a crude test, but a promising one at that! (Normally isolated servers are used, and a bunch of effort goes into the scenarios and analysis). The results are listed below, and the code is up on codeplex.

Local Run

Key Indicators

Counter

Instance

Category

Computer

Color

Range

Min

Max

Avg

User Load

_Total

LoadTest:Scenario

XPS720

1,000

10

630

315

Requests/Sec

_Total

LoadTest:Request

XPS720

1,000

0

411

231

Avg. Response Time

_Total

LoadTest:Request

XPS720

10

0.0053

1.07

0.18

Errors/Sec

_Total

LoadTest:Errors

XPS720

0

0

0

0

Threshold Violations/Sec

_Total

LoadTest:Errors

XPS720

1

0

0.20

0.070

Controller and Agents

Counter

Instance

Category

Computer

Color

Range

Min

Max

Avg

% Processor Time

_Total

Processor

XPS720

100

4.85

99.9

63.8

Available MBytes

-

Memory

XPS720

1,000

829

908

863

Remote Run

Key Indicators

Counter

Instance

Category

Computer

Color

Range

Min

Max

Avg

User Load

_Total

LoadTest:Scenario

XPS720

1,000

10

410

210

Requests/Sec

_Total

LoadTest:Request

XPS720

1,000

8.00

286

164

Avg. Response Time

_Total

LoadTest:Request

XPS720

1

0.0086

0.38

0.094

Errors/Sec

_Total

LoadTest:Errors

XPS720

0

0

0

0

Threshold Violations/Sec

_Total

LoadTest:Errors

XPS720

1

0

0.20

0.058

Controller and Agents

Counter

Instance

Category

Computer

Color

Range

Min

Max

Avg

% Processor Time

_Total

Processor

XPS720

100

5.65

98.1

59.2

Available MBytes

-

Memory

XPS720

10,000

936

1,036

988

posted @ Sunday, January 11, 2009 1:32 AM | Feedback (1) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Thursday, January 08, 2009

Using a Recursive Expression to Create an Html Menu

I find recursive expression to be really useful. They are particularly handy when dealing with parent child relationships. As a demonstration, see a potential method for generating a site map below:

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Text;

    5 

    6 namespace SiteMapDemo

    7 {

    8     class MenuItem

    9     {

   10         public Guid ID { get; set; }

   11         public Guid? ParentID { get; set; }

   12         public string Name { get; set; }

   13         public string Path { get; set; }

   14         public int Rank { get; set; }

   15     }

   16     class Program

   17     {

   18         static void Main(string[] args)

   19         {

   20             List<MenuItem> menu = new List<MenuItem>(new[]{

   21                 new MenuItem{ID = Guid.NewGuid(), Name = "First", ParentID=null, Path="/", Rank=0},

   22                 new MenuItem{ID = Guid.NewGuid(), Name = "Second", ParentID=null, Path="/second.aspx",Rank=1},

   23             });

   24             menu.AddRange(new[] {

   25                 new MenuItem{ID = Guid.NewGuid(), Name = "FirstSub", ParentID=menu[0].ID, Path="/firstsub.aspx",Rank=0},

   26                 new MenuItem{ID = Guid.NewGuid(), Name = "SecondSub", ParentID=menu[0].ID, Path="/secondsub.aspx",Rank=1},

   27                 });

   28             Func<List<MenuItem>, Guid?, string> renderMenu = null;

   29             renderMenu = (menus, Parent) =>

   30             {

   31                 var sub = menus.Where(m => m.ParentID == Parent).OrderBy(s => s.Rank).ToList();

   32                 if (sub.Count > 0)

   33                 {

   34                     StringBuilder sb = new StringBuilder();

   35                     sub.ForEach(s => { sb.Append(String.Format("<li><a href=\"{0}\">{1}</a>{2}</li>", s.Path, s.Name, renderMenu(menus, s.ID))); });

   36                     return sb.ToString();

   37                 }

   38                 return "";

   39             };

   40             Console.Write(renderMenu(menu, null));

   41             Console.ReadLine();

   42         }

   43     }

   44 }

The output:

<li><a href="http://www.charlesrcook.com/">First</a></li><li><a href="http://www.charlesrcook.com/firstsub.aspx">FirstSub</a></li><li><a href="/secondsub.aspx">SecondSub</a></li><li><a href="http://www.charlesrcook.com/second.aspx">Second</a></li>

posted @ Thursday, January 08, 2009 7:40 PM | Feedback (1) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Sunday, January 04, 2009

Paging with Filters and Sorts added to Unifico

Two new additions were added to Unifico: filtering on fields and sorting on fields with the help of Html Extension methods.

A PagingSet class was defined to contain configuration options for the paging. In this way a View can still page on more than one list and maintain complete control over the Html rendered. Every string used in the Html Helpers is pulled from the configuration (A default is made available).

Several extension methods were added to the Html Helper to make rendering the controls easier.

The filtering html form can be rendered with <%= Html.FilterInput(Paging, "Go") %> Where "go" is the button text.

A sortable column header can be rendered with <%= Html.PageSorting(Paging, "Email","E-Mail")%>

Where the paging configuration has been passed from the controller, leaving the paging control completely in the hands of the controller:

<% PageResponse<User> Users = (PageResponse<User>)ViewData.Model;

PagingSet Paging = (PagingSet)ViewData["PagingSet"];

%>

View the complete "View" here, http://www.codeplex.com/unifico/SourceControl/changeset/view/1798#54414

View the complete Controller here, http://www.codeplex.com/unifico/SourceControl/changeset/view/1798#44699

The end result of all this is paging that executes through the PageRequest class, so that no changes are required of the Service and paging that executes in SQL. It also has the nice benefit of residing completely in the QueryString and not requiring changes to the Controller's Action's parameters.

An example path created from paging with sorting and filtering: /Admin/Account/Users?expr=asdf9&filterby=All&orderby=Name&asc=False&page=1

And the SQL it generates.

exec sp_executesql N'SELECT TOP (10) [t0].[UserID] AS [ID], [t0].[Name], [t0].[Password], [t0].[Email]
FROM [dbo].[User] AS [t0]
WHERE ([t0].[Name] = @p0) OR ([t0].[Name] = @p1)
ORDER BY [t0].[Name] DESC',N'@p0 nvarchar(5),@p1 nvarchar(5)',@p0=N'asdf9',@p1=N'asdf9'

posted @ Sunday, January 04, 2009 6:25 PM | Feedback (5) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Saturday, January 03, 2009

Unifico’s Account Component Gets an Admin

The Account Component in the Unifico Framework which is serving as a sample component now has an admin. Two supporting developments for the admin are also up: the paging HtmlHelper and overridable embedded views. Allowing for the embedded views to be overridden by placing new views in App.Web greatly eases development and should help in Component maintenance and versioning (new views can be made without rebuilding the component). I am also rather happy with the eas to which views are made overridable.

The paging turned out quite well, a few changes to the PageResponse<T> to implement IPageable made things fit really nicely. For example if PageResponse<User> is passed to the view from the controller, the paging can be generated with default settings in the snippet below. I also made use of my QueryString extension methods to make it work with populated QueryStrings (and have support for many pagers).

<%= Html.PageListing(Users) %>

 

http://www.codeplex.com/unifico

posted @ Saturday, January 03, 2009 10:45 PM | Feedback (1) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Friday, January 02, 2009

Allowing for Dynamic Embedded View Substitution with MVC

A while back I found an interesting post on embedding resources in MVC at "The Glass is Too Big" (http://www.wynia.org/wordpress/2008/12/05/aspnet-mvc-plugins/). Following the method was straightforward and allowed views to be embedded within a Component Class Library. Well, two extra items would be nice. It would be nice to not have to write that large plug-in path, and if a view was defined in the views folder it would be returned in lieu of the embedded view.

Adding this support required two modifications. First the AssemblyResourceProvider was modified to check for the view's existence by adding a Regex pattern match and checking for the file. If the file is found within the view folder, the file is returned, if not the embedded resource will return.

 

   58             // Check to see if a file has been added to the views folder.  If so, return that view.

   59             Match m = Regex.Match(path, @"~/Plugin/[\w\.]+.dll/([\w\.]+).Views.([\w\.]+).aspx");

   60             if (m.Success)

   61             {

   62                 string assemblyMatch = m.Groups[1].Value;

   63                 string viewPath = m.Groups[2].Value;

   64                 string physicalPath = HttpContext.Current.Server.MapPath(String.Format("~/Views/{0}/{1}.aspx",

   65                     assemblyMatch, viewPath.Replace(".", "/")));

   66                 if (File.Exists(physicalPath))

   67                     return File.Open(physicalPath,FileMode.Open);

   68             }

http://www.codeplex.com/unifico/SourceControl/changeset/view/1491#9855

 

To avoid having to write out the plug-in strings I wrote an extension method to write it and return the ViewResult. Reflection is used to gather the assembly name.

 

    9     public static class ControllerPluginPathExtender

   10     {

   11         public static ViewResult PluginView(this Controller controller)

   12         {

   13             string controllerName = controller.RouteData.GetRequiredString("controller");

   14             string viewName = controller.RouteData.GetRequiredString("action");

   15             string assemblyName = controller.GetType().Assembly.FullName.Split(',')[0];

   16             string pluginPath = String.Format(

   17                     @"~/Plugin/{0}.dll/{0}.Views.{1}.{2}.aspx",

   18                     assemblyName,controllerName,viewName

   19                     );

   20             return new ViewResult{

   21                 ViewName = pluginPath

   22             };

   23         }

   24     }

http://www.codeplex.com/unifico/SourceControl/changeset/view/1491#52892

Now using the embedded option is less tedious, for example:

 

   33 

   34         [Authorize(Roles="Admin")]

   35         public ActionResult Index()

   36         {

   37             ViewData["Title"] = "Account Admin Home";

   38             ViewData["Message"] = "Welcome to the account admin";

   39 

   40             return this.PluginView();

   41             //return View("~/Plugin/App.Account.dll/App.Account.Views.Admin.Index.aspx");

   42         }

 

It would be nice to not have to use 'this', but I can't see a way around it without rebuilding MVC, not something I want to start doing. Also some caching and less reflection might be nice.



Update: The VewData and TempData have to be added to pass the models to the view

   11         public static ViewResult PluginView(this Controller controller)

   12         {

   13             string controllerName = controller.RouteData.GetRequiredString("controller");

   14             string viewName = controller.RouteData.GetRequiredString("action");

   15             string assemblyName = controller.GetType().Assembly.FullName.Split(',')[0];

   16             string pluginPath = String.Format(

   17                     @"~/Plugin/{0}.dll/{0}.Views.{1}.{2}.aspx",

   18                     assemblyName,controllerName,viewName

   19                     );

   20             return new ViewResult{

   21                 ViewName = pluginPath,

   22                 ViewData = controller.ViewData,

   23                 TempData = controller.TempData

   24             };

   25         }

posted @ Friday, January 02, 2009 10:18 PM | Feedback (5) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Wednesday, December 31, 2008

Paging Helpers in Unifico, Filtered and Sorted Paging

Unifico has a few paging helpers to make service methods easily paged from a client. Essentially the framework makes consuming a page request object as simple as calling .ToList() on an IQueryable source. The object, the PageRequest, has two collections, Filters and Sorts with several constructors to make instantiation easy. The collections are rather straight forward, providing filtering and sorting ability on a paging source. The uniqueness comes from the ability to request multiple filters and sorts together, along with a paging request. This request is then execute on the IQueryable source, so if DLINQ is used, results in exactly two database hits. A COUNT statement is executed to find out how many pages there are, and a single select statement providing the paged results. This is all done without exposing LINQ or IQueryable to the service's client.

Making an existing source page-able is rather simple, compare the two implementations.

Without paging implemented:

 

   44         public List<App.Account.Models.Role> GetRoles()

   45         {

   46             return accountRepository.GetRoles().ToList();

   47         }

 

 

With paging implemented:

 

   43         public PageResponse<App.Account.Models.Role> GetRolePage(PageRequest PageRequest)

   44         {

   45             return accountRepository.GetRoles().ToPageResponse(PageRequest);

   46         }

 

 

Utilizing the paging is almost painfully easy.

Grabbing the first page at a size of ten:

 

  120 PageResponse<Role> rolePage = accountService.GetRolePage(new PageRequest(0, 10));

 

 

Or grabbing the first page sorting by the role's name (ascending):

 

  120             PageResponse<Role> rolePage = accountService.GetRolePage(new PageRequest(0, 10, "Name", "string", true));

 

 

Or fully defining the page request:

 

  120             accountService.GetRolePage(new PageRequest

  121             {

  122                 Index = 2,

  123                 PageSize = 10,

  124                 Filters = new ContractList<Filter>(

  125                     new[]{new Filter { BinaryExpression=FilterBinaryExpression.Equal, Parameter="Name", TypeName="String",Value="Admin"},

  126                         new Filter { BinaryExpression=FilterBinaryExpression.GreaterThan, Parameter="Level", TypeName="Int32", Value=1}}),

  127                 Sorts = new ContractList<Sort>(

  128                     new[] { new Sort { Ascending = true, TypeName = "Int32", Parameter = "Level" } })

  129             });

  130             /* Executes

  131             SELECT [t1].[RoleID] AS [ID], [t1].[Name], [t1].[Level] AS [Level]

  132             FROM (

  133                 SELECT ROW_NUMBER() OVER (ORDER BY [t0].[Level]) AS [ROW_NUMBER], [t0].[RoleID], [t0].[Name], [t0].[Level]

  134                 FROM [dbo].[Role] AS [t0]

  135                 WHERE ([t0].[Level] > 1) AND ([t0].[Name] = 'Admin')

  136                 ) AS [t1]

  137             WHERE [t1].[ROW_NUMBER] BETWEEN 20 + 1 AND 20 + 10

  138             ORDER BY [t1].[ROW_NUMBER]

  139             */

 

 

I'm sure you have notice the TypeName properties and wondered why they are there. They enable the helper's methods to work with the expression tree before the query has been executed. Notice that the paging occurs in SQL against the table names and columns, not against the models. While the syntax is nowhere near that of LINQ, it seals of the service and keeps the paging responsibility within the service without requiring the service to handle specific paging requests. A similar method can be used to search multiple sources, and will be added shortly. Ohh, and it works across WCF.

 

The Unifico Framework

posted @ Wednesday, December 31, 2008 8:59 PM | Feedback (5) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

The Unifico Framework’s Organization

One major aspect to Unifico is its organization through assemblies and namespacing. Assemblies are 'cut' by component to allow for component plug-ability. One major goal of the project is to allow for a component to be easily added to an existing site without conflicting with other equally significant components. With a few modifications (to come) Unifico allows for a whole component to be dropped in as a dll without recompilation by virtue of Structure Map. Currently, each component's assembly has to be added to structure map in a common class, the 'bootstrapper'.

Within each component there are several namespaces, which are critical to understanding a component.

  • App.Component.Controllers – Where ASP.NET MVC Controllers for the component are placed. These are clients to the service.
  • App.Component.DataAccess.Interfaces – The interfaces for the data repository(s). These are usually rather small, with a Save, Delete and Get for each model.
  • App.Component.DataAccess.SqlServer –Where the SQL specific implementation of the interface resides.
  • App.Component.Diagrams – Contains the class diagrams for the component's models.
  • App.Component.HttpModules – An optional namespace where any HttpModules for the component would reside.
  • App.Component.Models – A namespace containing the models for the component. Models are serialized when remoting is used.
  • App.Component.Models.Forms – Contains the 'Form Models', essentially requests to perform an action. For example a 'UserForm' would be populated and sent to the UserService to request a new User.
  • App.Component.Service – Defines the service for the component. It is here where the WCF and in-process service definitions are located. The 'real work' of a component is defined within the service implementation.
  • App.Component.Views – Contains any embedded views for the component. Embedding views are optional, but are used in the examples provided.

Without delving into details, that introduces the parts of a component's organization. Another aspect to a component is its physical organization. That is, where are various parts hosted in a distributed situation? The physical boundaries are defined by the interfaces, particularly the service interfaces. Within the service the application is hosted on the WCF service host. Outside of the service the application is hosted within the website.

Though very brief, I hope this helps anyone taking a look at the code. As always, any thoughts are appreciated.

posted @ Wednesday, December 31, 2008 7:16 PM | Feedback (0) | Filed Under [ Web Programming ]

kick it on DotNetKicks.com

Powered by: