tag:blogger.com,1999:blog-29334018489654985442024-03-05T02:02:46.462-05:00Sit Down Waldo!tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.comBlogger32125tag:blogger.com,1999:blog-2933401848965498544.post-77206032064331977282011-09-21T13:39:00.001-04:002011-09-21T13:39:39.280-04:00jQuery UI Frame Dialog - Loading Pane–Revisited<p><a href="http://tdanryan.com/demo/framedialog/framedialogswing00.html">Demo</a></p> <p>It’s been awhile since I modified the jQuery UI Frame Dialog plugin to include a loading image/css to display while the iFrame’s content is loaded. My original post is located <a href="http://tdryan.blogspot.com/2010/09/jquery-ui-frame-dialog-loading-pane.html">here</a>.</p> <p>I’ve noticed (so have others <a href="http://bugs.jqueryui.com/ticket/5166">here</a>, <a href="http://forum.jquery.com/topic/ui-dialog-with-iframe">here</a>, etc…) that the iFrame’s content is requested multiple times. If you’re interest in the reasons why the iFrame’s content is loaded multiple times, you can read about it <a href="http://bugs.jqueryui.com/ticket/5166">here</a> and <a href="http://forum.jquery.com/topic/ui-dialog-with-iframe">here</a>. I’ve modified the plugin to avoid the multiple loads issue. The modified JavaScript file can be downloaded by viewing source on the demo page <a href="http://tdanryan.com/demo/framedialog/framedialogswing00.html">here</a>.</p> <p>Again, I’ve tried to contact the original jQuery UI Frame Dialog’s author; however I’ve been unsuccessful. So, rather than take ownership of the plugin, I’ve modified the version number with a .# extension that will serve as the version number of my modifications. So, this specific version of the plugin has a file name of: jquery-framedialog-1.1.2.1.js.</p> <p>I’ve tested the modified plugin on IE 8/9, Firefox 6.0.2, and Chrome 14.0.835.163 and it appears to be avoiding the multiple load issue.</p> <p>Thanks for reading… </p> <p><a href="http://tdanryan.com/demo/framedialog/framedialogswing00.html">Demo</a></p> tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com4tag:blogger.com,1999:blog-2933401848965498544.post-9091832655292315952011-08-12T17:42:00.002-04:002011-08-13T11:40:17.175-04:00HttpPostedFile.FileName Beware…Browser issues – you’ve gotta love them… <br />
<br />
Here’s the scenario…<br />
<br />
We have an application that allows users to upload spreadsheets. We parse the data in the spreadsheets to create new spreadsheets, save input to a data store, and a bunch of other useful functions. Once the application was deployed, we started to get bug/issue reports on how the uploads were failing. Typical user feedback: ‘…the Web site isn’t working;’ ‘…the uploading my database feature is broken;’ ‘…why can’t the Web site do it like Facebook?’ You get the idea…<br />
We narrowed it down to an IE issue. Most of the users were using IE8, while the developers were using Chrome, Firefox, and IE9. Of course, the file upload and resulting file parsing was working fine for the developers and testers. Why aren’t the users using Chrome, Firefox, IE9, Safari, etc…? Well, because they are users <img alt="Open-mouthed smile" class="wlEmoticon wlEmoticon-openmouthedsmile" src="http://lh3.ggpht.com/-MUWWqvHkW-o/TkWbfCwhqLI/AAAAAAAABOk/UboHVB-fTJM/wlEmoticon-openmouthedsmile%25255B2%25255D.png?imgmax=800" style="border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none;" /> Seriously though, the client’s organization is using IE8, so that’s what we should have used when developing and testing…<br />
<br />
Continuing on…We couldn’t replicate the issue using IE9 in IE8 or IE7 mode; however, the bug/issue reports kept piling in…<br />
<br />
Luckily, someone had an old VM with XP and IE8 installed. So, we did a quick test using IE8, and sure enough, the ugly bug revealed itself. Here’s a screenshot of what the YSOD could possibly look like (the paths and other revealing info is modified here, so the need for ‘possibly’).<br />
<br />
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGVx9JsUp7qoi9aHHQUHTH-SochfaQ1lRbIhbtDCCECQDQ2PSYJgyOTw18hZTX1ZbYcA6gU0UhPDXPr_yf4QObV1SMyzh6JfQzRvBkWFSj1jdRmGvbSyDHm7xn6mbsAxTKrtIH3dQPlYmt/s1600/httppostedfileerror.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGVx9JsUp7qoi9aHHQUHTH-SochfaQ1lRbIhbtDCCECQDQ2PSYJgyOTw18hZTX1ZbYcA6gU0UhPDXPr_yf4QObV1SMyzh6JfQzRvBkWFSj1jdRmGvbSyDHm7xn6mbsAxTKrtIH3dQPlYmt/s400/httppostedfileerror.PNG" width="400" /></a></div>
<br />
Beyond the browser issue frustration, we couldn’t walk the code with VS2010, because the XP/IE8 VM did not have VS2010 installed.<br />
<br />
What it all narrowed down to was how browsers offer up the file name (via HttpPostedFile.FileName property). All browsers (Chrome, FF, IE9, ...) but IE8- (IE8, 7, 6, ...) report ONLY the file name, while IE8- reports the fully qualified path on the client’s machine. The Fully Qualified Path (FQP) is the key here. Also, in IE9 in IE8 mode, the HttpPostedFile.FileName reports what IE9 would report and not IE8 (nice!).<br />
<br />
The following is a snippet of the existing code (attachmentPath is the directory where the file will be saved to on the Server):<br />
<br />
<div style="font-size: 11px;">
<pre class="brush: csharp">var fileName = Request.Files[i].FileName;
var filepath = Path.Combine(attachmentPath, fileName);
</pre>
</div>
<br />
Do you see the issue? Well, when testing in all browsers but IE8-, this will work fine. However, in IE8-, the aforementioned snippet will result with a filepath of something like the following: <br />
<br />
c:\directoryToStoreUploadedFiles\C:\Documents and Settings\xyz123\Desktop\ie8_testing.txt <br />
<br />
while we are expecting the following: <br />
<br />
c:\directoryToStoreUploadedFiles\ie8_testing.txt <br />
<br />
So, make sure to parse out the file name correctly using the System.IO.Path.GetFileName() method. This method will return ONLY to file name (removing the directory path if it pre-pended). <br />
<br />
The revised code snippet will work for all browsers: <br />
<br />
<div style="font-size: 11px;">
<pre class="brush: csharp">var postedFile = Request.Files[i];
var fileName = Path.GetFileName(postedFile.FileName);
var filepath = Path.Combine(attachmentPath, fileName);
</pre>
</div>
<br />
Now, we will always get what we are expecting. <br />
<br />
If we would have looked at the MSDN documentation for the HttpPostedFile class (who does that??) - <a href="http://msdn.microsoft.com/en-us/library/system.web.httppostedfile.filename.aspx">HttpPostedFile.FileName</a> – we would have found the following documentation for the FileName property:<br />
<br />
<h3>
HttpPostedFile.FileName Property</h3>
Gets the fully qualified name of the file on the client.<br />
<br />
Of course it does!?!? Not when the user is using Chrome, Firefox, IE9, or probably any other browser.<br />
<br />
Simple solution, yet very difficult to track down. Something you may want to file away in your toolbox... <br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-32199383781853257722011-05-16T11:49:00.001-04:002011-05-16T11:49:39.261-04:00NBuilder Extensions–US Address Randomizer– Make EF Code First Drop Database Less PainfulHave you used <a href="http://msdn.microsoft.com/en-us/data/aa937723">Entity Framework 4.1 Code First</a>? Specifically, have you used <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> with <a href="http://www.asp.net/mvc">ASP.NET MVC 3</a> and <a href="http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/">MvcScaffolding</a>? If you have, you’ve felt the pain associated with adding properties to your model class, re-generating the code, and the framework requiring dropping of your database table and all the data that the table contains. I’ve heard that Microsoft is planning of a solution to this, but in the meantime, we’re stuck with it…<br />
<br />
A couple months ago, a colleague of mine recommended that I try out <a href="http://nbuilder.org/">NBuilder</a>. <br />
<br />
<a href="http://nbuilder.org/">NBuilder</a> makes the aforementioned <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> pains suck less. Less meaning that the pains still suck, but they are more tolerable. If you’re not familiar with <a href="http://nbuilder.org/">NBuilder</a>, the <a href="http://nbuilder.org/">NBuilder</a> Website describes <a href="http://nbuilder.org/">NBuilder</a> as the following:<br />
<br />
“Through a fluent, extensible interface, <a href="http://nbuilder.org/">NBuilder</a> allows you to rapidly create test data, automatically assigning values to properties and public fields that are of type of the built in .NET data types (e.g. ints and strings). <a href="http://nbuilder.org/">NBuilder</a> allows you to override for properties you are interested in using lambda expressions.”<br />
<br />
That is exactly what it is. But, how does it help <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> dropping tables requirement suck less? Well, you can create an database initializer class that derives from DropCreateDatabaseIfModelChanges<T>, where T is your DbContext class, that contains a Seed method that will insert data into your data tables. More on this later… If you’re lost and/or not familiar with any of these terms (with the exception of NBuilder), I recommend that you check out Steve Sanderson’s Mix 11 cast: <a href="http://channel9.msdn.com/events/MIX/MIX11/FRM13">Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More</a>.<br />
<br />
BTW, <a href="http://nbuilder.org/">NBuilder</a> is available via <a href="http://nuget.codeplex.com/">NuGet</a>.<br />
<br />
<a href="http://nbuilder.org/">NBuilder</a> contains facilities to randomly generate all kinds of data and data types including primitive types, phone numbers, date and time, first name, last name, addresses, etc... NBuilder also contains address randomizers; however, the randomizer supporting US addresses is not quite as useful as the randomizer for UK addresses. Therefore, I created a class to generate more useful US addresses. Below is a class snippet for this US address randomizer:<br />
<strike></strike> <br />
<h4>UsAddressRandomizer</h4><div style="font-size: 11px;"><pre class="brush: csharp">using System.Collections.Generic;
using FizzWare.NBuilder.Generators;
namespace FizzWare.NBuilder
{
public class UsAddressRandomizer
{
private static readonly IRandomGenerator Generator = new RandomGenerator();
#region Data Generation
private static readonly List<UsAddressFake> States =
new List<UsAddressFake>
{
new UsAddressFake { StateName = "Alaska", StateCode = "AK", ZipRangeBegin = 99500, ZipRangeEnd = 99999},
new UsAddressFake { StateName = "Alabama", StateCode = "AL", ZipRangeBegin = 35000, ZipRangeEnd = 36999},
new UsAddressFake { StateName = "Arkansas", StateCode = "AR", ZipRangeBegin = 71600, ZipRangeEnd = 72999},
new UsAddressFake { StateName = "Arizona", StateCode = "AZ", ZipRangeBegin = 85000, ZipRangeEnd = 86599},
new UsAddressFake { StateName = "California", StateCode = "CA", ZipRangeBegin = 90000, ZipRangeEnd = 96699},
new UsAddressFake { StateName = "Colorado", StateCode = "CO", ZipRangeBegin = 80000, ZipRangeEnd = 81699},
new UsAddressFake { StateName = "Connecticut", StateCode = "CT", ZipRangeBegin = 6000, ZipRangeEnd = 6999},
new UsAddressFake { StateName = "Delaware", StateCode = "DE", ZipRangeBegin = 19700, ZipRangeEnd = 19999},
new UsAddressFake { StateName = "Florida", StateCode = "FL", ZipRangeBegin = 32000, ZipRangeEnd = 34999},
new UsAddressFake { StateName = "Georgia", StateCode = "GA", ZipRangeBegin = 30000, ZipRangeEnd = 31999},
new UsAddressFake { StateName = "Hawaii", StateCode = "HI", ZipRangeBegin = 96700, ZipRangeEnd = 96899},
new UsAddressFake { StateName = "Iowa", StateCode = "IA", ZipRangeBegin = 50000, ZipRangeEnd = 52899},
new UsAddressFake { StateName = "Idaho", StateCode = "ID", ZipRangeBegin = 83200, ZipRangeEnd = 83899},
new UsAddressFake { StateName = "Illinois", StateCode = "IL", ZipRangeBegin = 60000, ZipRangeEnd = 62999},
new UsAddressFake { StateName = "Indiana", StateCode = "IN", ZipRangeBegin = 46000, ZipRangeEnd = 47999},
new UsAddressFake { StateName = "Kansas", StateCode = "KS", ZipRangeBegin = 66000, ZipRangeEnd = 67999},
new UsAddressFake { StateName = "Kentucky", StateCode = "KY", ZipRangeBegin = 40000, ZipRangeEnd = 42799},
new UsAddressFake { StateName = "Louisiana", StateCode = "LA", ZipRangeBegin = 70000, ZipRangeEnd = 71499},
new UsAddressFake { StateName = "Massachusetts", StateCode = "MA", ZipRangeBegin = 1000, ZipRangeEnd = 2799},
new UsAddressFake { StateName = "Maryland", StateCode = "MD", ZipRangeBegin = 20600, ZipRangeEnd = 21999},
new UsAddressFake { StateName = "Maine", StateCode = "ME", ZipRangeBegin = 3900, ZipRangeEnd = 4999},
new UsAddressFake { StateName = "Michigan", StateCode = "MI", ZipRangeBegin = 48000, ZipRangeEnd = 49999},
new UsAddressFake { StateName = "Minnesota", StateCode = "MN", ZipRangeBegin = 55000, ZipRangeEnd = 56799},
new UsAddressFake { StateName = "Missouri", StateCode = "MO", ZipRangeBegin = 63000, ZipRangeEnd = 65899},
new UsAddressFake { StateName = "Mississippi", StateCode = "MS", ZipRangeBegin = 38600, ZipRangeEnd = 39799},
new UsAddressFake { StateName = "Montana", StateCode = "MT", ZipRangeBegin = 59000, ZipRangeEnd = 59999},
new UsAddressFake { StateName = "North Carolina", StateCode = "NC", ZipRangeBegin = 26900, ZipRangeEnd = 28999},
new UsAddressFake { StateName = "North Dakota", StateCode = "ND", ZipRangeBegin = 58000, ZipRangeEnd = 58899},
new UsAddressFake { StateName = "Nebraska", StateCode = "NE", ZipRangeBegin = 68000, ZipRangeEnd = 69399},
new UsAddressFake { StateName = "New Hampshire", StateCode = "NH", ZipRangeBegin = 3000, ZipRangeEnd = 3999},
new UsAddressFake { StateName = "New Jersey", StateCode = "NJ", ZipRangeBegin = 7000, ZipRangeEnd = 8999},
new UsAddressFake { StateName = "New Mexico", StateCode = "NM", ZipRangeBegin = 87000, ZipRangeEnd = 88499},
new UsAddressFake { StateName = "Nevada", StateCode = "NV", ZipRangeBegin = 88900, ZipRangeEnd = 89899},
new UsAddressFake { StateName = "New York", StateCode = "NY", ZipRangeBegin = 500, ZipRangeEnd = 6399},
new UsAddressFake { StateName = "Ohio", StateCode = "OH", ZipRangeBegin = 43000, ZipRangeEnd = 45999},
new UsAddressFake { StateName = "Oklahoma", StateCode = "OK", ZipRangeBegin = 73000, ZipRangeEnd = 74999},
new UsAddressFake { StateName = "Oregon", StateCode = "OR", ZipRangeBegin = 97000, ZipRangeEnd = 97999},
new UsAddressFake { StateName = "Pennsylvania", StateCode = "PA", ZipRangeBegin = 15000, ZipRangeEnd = 19699},
new UsAddressFake { StateName = "Rhode Island", StateCode = "RI", ZipRangeBegin = 2800, ZipRangeEnd = 2999},
new UsAddressFake { StateName = "South Carolina", StateCode = "SC", ZipRangeBegin = 29000, ZipRangeEnd = 29999},
new UsAddressFake { StateName = "South Dakota", StateCode = "SD", ZipRangeBegin = 57000, ZipRangeEnd = 57799},
new UsAddressFake { StateName = "Tennessee", StateCode = "TN", ZipRangeBegin = 37000, ZipRangeEnd = 38599},
new UsAddressFake { StateName = "Texas", StateCode = "TX", ZipRangeBegin = 75000, ZipRangeEnd = 79999},
new UsAddressFake { StateName = "Utah", StateCode = "UT", ZipRangeBegin = 84000, ZipRangeEnd = 84799},
new UsAddressFake { StateName = "Vermont", StateCode = "VT", ZipRangeBegin = 5000, ZipRangeEnd = 5999},
new UsAddressFake { StateName = "Virginia", StateCode = "VA", ZipRangeBegin = 22000, ZipRangeEnd = 24699},
new UsAddressFake { StateName = "Washington", StateCode = "WA", ZipRangeBegin = 98000, ZipRangeEnd = 99499},
new UsAddressFake { StateName = "Wisconsin", StateCode = "WI", ZipRangeBegin = 53000, ZipRangeEnd = 54999},
new UsAddressFake { StateName = "West Virginia", StateCode = "WV", ZipRangeBegin = 24700, ZipRangeEnd = 26899},
new UsAddressFake { StateName = "Wyoming", StateCode = "WY", ZipRangeBegin = 82000, ZipRangeEnd = 83199}
};
private static readonly List<string> Cities =
new List<string>
{
"Abington",
"Acton",
"Acushnet",
"Adams",
"Agawam",
"Alford",
"Amesbury",
"Amherst",
"Andover",
"Aquinnah",
"Arlington",
"Ashburnham",
"Ashby",
"Ashfield",
"Ashland",
"Athol",
"Attleboro",
"Auburn",
"Avon",
"Ayer",
"Barnstable",
"Barre",
"Becket",
"Bedford",
"Belchertown",
"Bellingham",
"Belmont",
"Berkley",
"Berlin",
"Bernardston",
"Beverly",
"Billerica",
"Blackstone",
"Blandford",
"Bolton",
"Boston",
"Bourne",
"Boxborough",
"Boxford",
"Boylston",
"Braintree",
"Brewster",
"Bridgewater",
"Brimfield",
"Brockton",
"Brookfield",
"Brookline",
"Buckland",
"Burlington",
"Cambridge",
"Canton",
"Carlisle",
"Carver",
"Charlemont",
"Charlton",
"Chatham",
"Chelmsford",
"Chelsea",
"Cheshire",
"Chester",
"Chesterfield",
"Chicopee",
"Chilmark",
"Clarksburg",
"Clinton",
"Cohasset",
"Colrain",
"Concord",
"Conway",
"Cummington",
"Dalton",
"Danvers",
"Dartmouth",
"Dedham",
"Deerfield",
"Dennis",
"Dighton",
"Douglas",
"Dover",
"Dracut",
"Dudley",
"Dunstable",
"Duxbury",
"East Bridgewater",
"East Brookfield",
"East Longmeadow",
"Eastham",
"Easthampton",
"Easton",
"Edgartown",
"Egremont",
"Erving",
"Essex",
"Everett",
"Fairhaven",
"Fall River",
"Falmouth",
"Fitchburg",
"Florida",
"Foxborough",
"Framingham",
"Franklin",
"Freetown",
"Gardner",
"Georgetown",
"Gill",
"Gloucester",
"Goshen",
"Gosnold",
"Grafton",
"Granby",
"Granville",
"Great Barrington",
"Greenfield",
"Groton",
"Groveland",
"Hadley",
"Halifax",
"Hamilton",
"Hampden",
"Hancock",
"Hanover",
"Hanson",
"Hardwick",
"Harvard",
"Harwich",
"Hatfield",
"Haverhill",
"Hawley",
"Heath",
"Hingham",
"Hinsdale",
"Holbrook",
"Holden",
"Holland",
"Holliston",
"Holyoke",
"Hopedale",
"Hopkinton",
"Hubbardston",
"Hudson",
"Hull",
"Huntington",
"Ipswich",
"Kingston",
"Lakeville",
"Lancaster",
"Lanesborough",
"Lawrence",
"Lee",
"Leicester",
"Lenox",
"Leominster",
"Leverett",
"Lexington",
"Leyden",
"Lincoln",
"Littleton",
"Longmeadow",
"Lowell",
"Ludlow",
"Lunenburg",
"Lynn",
"Lynnfield",
"Malden",
"Manchester-by-the-Sea",
"Mansfield",
"Marblehead",
"Marion",
"Marlborough",
"Marshfield",
"Mashpee",
"Mattapoisett",
"Maynard",
"Medfield",
"Medford",
"Medway",
"Melrose",
"Mendon",
"Merrimac",
"Methuen",
"Middleborough",
"Middlefield",
"Middleton",
"Milford",
"Millbury",
"Millis",
"Millville",
"Milton",
"Monroe",
"Monson",
"Montague",
"Monterey",
"Montgomery",
"Mount Washington",
"Nahant",
"Nantucket",
"Natick",
"Needham",
"New Ashford",
"New Bedford",
"New Braintree",
"New Marlborough",
"New Salem",
"Newbury",
"Newburyport",
"Newton",
"Norfolk",
"North Adams",
"North Andover",
"North Attleborough",
"North Brookfield",
"North Reading",
"Northampton",
"Northborough",
"Northbridge",
"Northfield",
"Norton",
"Norwell",
"Norwood",
"Oak Bluffs",
"Oakham",
"Orange",
"Orleans",
"Otis",
"Oxford",
"Palmer",
"Paxton",
"Peabody",
"Pelham",
"Pembroke",
"Pepperell",
"Peru",
"Petersham",
"Phillipston",
"Pittsfield",
"Plainfield",
"Plainville",
"Plymouth",
"Plympton",
"Princeton",
"Provincetown",
"Quincy",
"Randolph",
"Raynham",
"Reading",
"Rehoboth",
"Revere",
"Richmond",
"Rochester",
"Rockland",
"Rockport",
"Rowe",
"Rowley",
"Royalston",
"Russell",
"Rutland",
"Salem",
"Salisbury",
"Sandisfield",
"Sandwich",
"Saugus",
"Savoy",
"Scituate",
"Seekonk",
"Sharon",
"Sheffield",
"Shelburne",
"Sherborn",
"Shirley",
"Shrewsbury",
"Shutesbury",
"Somerset",
"Somerville",
"South Hadley",
"Southampton",
"Southborough",
"Southbridge",
"Southwick",
"Spencer",
"Springfield",
"Sterling",
"Stockbridge",
"Stoneham",
"Stoughton",
"Stow",
"Sturbridge",
"Sudbury",
"Sunderland",
"Sutton",
"Swampscott",
"Swansea",
"Taunton",
"Templeton",
"Tewksbury",
"Tisbury",
"Tolland",
"Topsfield",
"Townsend",
"Truro",
"Tyngsborough",
"Tyringham",
"Upton",
"Uxbridge",
"Wakefield",
"Wales",
"Walpole",
"Waltham",
"Ware",
"Wareham",
"Warren",
"Warwick",
"Washington",
"Watertown",
"Wayland",
"Webster",
"Wellesley",
"Wellfleet",
"Wendell",
"Wenham",
"West Boylston",
"West Bridgewater",
"West Brookfield",
"West Newbury",
"West Springfield",
"West Stockbridge",
"West Tisbury",
"Westborough",
"Westfield",
"Westford",
"Westhampton",
"Westminster",
"Weston",
"Westport",
"Westwood",
"Weymouth",
"Whately",
"Whitman",
"Wilbraham",
"Williamsburg",
"Williamstown",
"Wilmington",
"Winchendon",
"Winchester",
"Windsor",
"Winthrop",
"Woburn",
"Worcester",
"Worthington",
"Wrentham",
"Yarmouth"
};
private static readonly List<string> Streets =
new List<string>
{
"107th Street",
"10th Avenue",
"10th Street",
"11th Avenue",
"11th Street",
"12th Avenue",
"12th Street",
"137th Street",
"13th Street",
"14th Road",
"14th Street",
"17th Street",
"181st Street",
"18th Street",
"19th Street",
"1st Avenue",
"1st Street",
"23rd Street",
"25th Street",
"2nd Avenue",
"2nd Street",
"30th Avenue",
"31st Street",
"33rd Street",
"34th Avenue",
"35th Avenue",
"35th Street",
"36th Street",
"37th Avenue",
"39th Avenue",
"3rd Avenue",
"3rd Street",
"45th Avenue",
"47th Avenue",
"4th Avenue",
"4th Street",
"51st Avenue",
"52 Chambers Street",
"52nd Street",
"5th Avenue",
"5th Street",
"68th Street",
"6th Avenue",
"6th Street",
"76th Street",
"77th Street",
"78th Street",
"79th Street",
"7th Avenue",
"7th Avenue South",
"7th Street",
"80th Street",
"81st Street",
"82nd Street",
"83rd Street",
"84th Street",
"85th Street",
"86th Street",
"87th Street",
"88th Street",
"8th Avenue",
"8th Street",
"90th Avenue",
"90th Street",
"9th Avenue",
"9th Street",
"Abingdon Square",
"Adelphi Street",
"Albemarle Road",
"Albemarle Terrace",
"Alexander Avenue",
"Amboy Road",
"Amity Street",
"Amsterdam Avenue",
"Andrews Avenue",
"Argyle Road",
"Arthur Kill Road",
"Ashland Place",
"Astor Place",
"Atlantic Avenue",
"Available",
"Avenue A",
"Avenue Of Americas",
"Avenue Of The Americas",
"Avenue Z",
"Bainbridge Street",
"Baltic Street",
"Bank Street",
"Barclay Street",
"Barrow Street",
"Baxter Street",
"Beach 124th Street",
"Beach Street",
"Beaver Road",
"Beaver Street",
"Beck Street",
"Bedford Avenue",
"Bedford Street",
"Beekman Place",
"Beekman Street",
"Bergen Street",
"Berkeley Place",
"Bethune Street",
"Bicycle Racks",
"Bleecker Street",
"Bond Street",
"Boston Road",
"Botanical Garden",
"Bowery Street",
"Bowling Green",
"Bowne Street",
"Bridge Street",
"Brielle Avenue",
"Brighton Beach Avenue",
"Broad Street",
"Broadway",
"Brooklyn Heights",
"Broome Street",
"Buckingham Road",
"Bushwick Avenue",
"Cadman Plaza West",
"Calyer Street",
"Cambridge Place",
"Canal Street",
"Carlton Avenue",
"Carroll Gardens Historic Distr",
"Carroll Place",
"Carroll Street",
"Central Park West",
"Central Avenue",
"Central Park West",
"Central Park North",
"Central Park South",
"Central Park West",
"Centre Street",
"Chambers Street",
"Charles Street",
"Charlton Street",
"Chatham Square",
"Chauncey Street",
"Cheever Place",
"Chelsea Square Park",
"Christopher Street",
"Chruch Street",
"Church Avenue",
"Church Street",
"City College",
"City Hall",
"Clark Street",
"Classon Avenue",
"Clay Avenue",
"Clermont Avenue",
"Clifton Place",
"Clinton Avenue",
"Clinton Street",
"Clove Road",
"Coenties Slip",
"College Place",
"Columbia Heights",
"Columbia Place",
"Columbia Street",
"Columbus Avenue",
"Columbus Street",
"Commerce Street",
"Congress Street",
"Convent Avenue",
"Cooper Square",
"Cornelia Street",
"Cornell Cemetery",
"Court Place",
"Court Square",
"Court Street",
"Cranberry Street",
"Cropsey Avenue",
"Crosby Street",
"Croton Aqueduct",
"Cumberland Street",
"Dalny Road",
"Dawson Street",
"Dean Street",
"Decatur Street",
"Degraw Street",
"Dekalb Avenue",
"Ditmars Boulevard",
"Ditmas Avenue",
"Dorchester Avenue",
"Doris Freedman Plaza",
"Doughty Street",
"Dover Street",
"Downing Street",
"Drinking Fountain",
"Duane Street",
"Dyre Avenue",
"Eagle Street",
"East 103rd Street",
"East 104th Street",
"East 106th Street",
"East 10th Street",
"East 110th Street",
"East 11th Street",
"East 121st Street",
"East 125th Street",
"East 12th Street",
"East 136th Street",
"East 139th Street",
"East 13th Street",
"East 140th Street",
"East 141st Street",
"East 14th Street",
"East 151st Street",
"East 156th Street",
"East 15th Street",
"East 161st Street",
"East 166th Street",
"East 16th Street",
"East 179th Street",
"East 17th Street",
"East 17th Stret",
"East 18th Street",
"East 19th Street",
"East 20th Street",
"East 21st Street",
"East 22nd Street",
"East 23rd Street",
"East 24th Street",
"East 29th Street",
"East 32nd Street",
"East 34th Street",
"East 35th Street",
"East 36th Street",
"East 3rd Street",
"East 41st Street",
"East 42nd Street",
"East 43rd Street",
"East 44th Street",
"East 45th Street",
"East 46th Street",
"East 48th Street",
"East 49th Street",
"East 4th Street",
"East 50th Street",
"East 52nd Street",
"East 53rd Street",
"East 54th Street",
"East 55th Street",
"East 56th Street",
"East 57th Street",
"East 58th Street",
"East 59th Street",
"East 60th Street",
"East 61st Street",
"East 62nd Street",
"East 63rd Street",
"East 64th Street",
"East 65th Street",
"East 66th Street",
"East 67th Street",
"East 68th Street",
"East 69th Street",
"East 6th Street",
"East 70th Street",
"East 71st Street",
"East 72nd Street",
"East 73rd Street",
"East 74th Street",
"East 75th Street",
"East 76th Street",
"East 77th Street",
"East 78th Street",
"East 79th Street",
"East 7th Street",
"East 80th Street",
"East 81st Street",
"East 82nd Street",
"East 83rd Street",
"East 84th Street",
"East 85th Street",
"East 86th Street",
"East 87th Street",
"East 88th Street",
"East 89th Street",
"East 8th Street",
"East 90th Street",
"East 91st Street",
"East 92dnd Street",
"East 92nd Street",
"East 93rd Street",
"East 94th Street",
"East 95th Street",
"East 96th Street",
"East 9th Street",
"East Broadway",
"East End Avenue",
"East Fordham Road",
"East Tremont Avenue",
"Eastern Parkway",
"Edgecombe Avenue",
"Eldridge Street",
"Elizabeth Street",
"Elk Street",
"Emmons Avenue",
"Ericsson Place",
"Everit Street",
"Exchange Place",
"Faile Street",
"Federal Plaza",
"Fenimore Street",
"Fifth Avenue",
"Fillmore Street",
"Fiske Place",
"Flagg Court",
"Flagg Place",
"Flatbush Avenue",
"Flatbush Malls",
"Foley Square",
"Fordham University",
"Forest Avenue",
"Fort Greene Avenue",
"Fort Greene Place",
"Fort Totten Avenue",
"Fort Washington Avenue",
"Franklin Avenue",
"Franklin Street",
"Frederick Douglas Boulevard",
"Front Street",
"Fulton Ferry Streets",
"Fulton Fish Market",
"Fulton Landing",
"Fulton Street",
"Gansevoort Street",
"Garden Place",
"Garfield Place",
"Gates Avenue",
"Gateway Boulevard",
"Gay Street",
"Grace Court",
"Grace Court Alley",
"Grace Street",
"Gracie Mansion",
"Gramercy Park East",
"Gramercy Park North",
"Gramercy Park South",
"Gramercy Park West",
"Gramercy Place",
"Grand Army Plaza",
"Grand Avenue",
"Grand Central Terminal",
"Grand Concourse",
"Grand Street",
"Grant Street",
"Great Jones Street",
"Great Kills Road",
"Green Wood Cemetery",
"Greene Avenue",
"Greene Street",
"Greenpoint Avenue",
"Greenport Road",
"Greenwich Avenue",
"Greenwich Mews",
"Greenwich Street",
"Greenwich Village",
"Grove Court",
"Grove Street",
"Guernsey Street",
"Hall Street",
"Hamilton Avenue",
"Hamilton Place",
"Hamilton Terrace",
"Hanover Square",
"Hanson Place",
"Harrison Street",
"Heberton Avenue",
"Henderson Place",
"Henry Hudson Parkway",
"Henry Street",
"Heritage Trail",
"Heritage Trails",
"Hester Street",
"Hewitt Place",
"Hicks Street",
"High Bridge Aqueduct",
"Horatio Street",
"Howard Street",
"Hoyt Street",
"Hubert Street",
"Hudson Street",
"Hunts Lane",
"Hunts Lane Alley",
"Hydrants",
"Hylan Boulevard",
"Independence Avenue",
"Irving Place",
"Jackson Avenue",
"Jackson Street",
"Jamaica Avenue",
"James Street",
"Jane Street",
"Jay Street",
"Jefferson Avenue",
"Jerome Avenue",
"John Street",
"Jones Street",
"Joralemon Street",
"Jumel Terrace",
"Kane Street",
"Kelly Street",
"Kenmore Terrace",
"Kent Street",
"King Street",
"Kings Highway",
"Kingsbridge Terrace",
"Lafayette Avenue",
"Lafayette Street",
"Laguardia Airport",
"Laight Street",
"Lefferts Avenue",
"Lefferts Homestead",
"Lefferts Place",
"Lefferts Road",
"Lenox Avenue",
"Leonard Street",
"Leroy Street",
"Lewis Avenue",
"Lexington Avenue",
"Liberty Street",
"Lighting",
"Lincoln Avenue",
"Lincoln Place",
"Lincoln Road",
"Linwood Street",
"Lispenard Street",
"Little Bay",
"Little Neck Parkway",
"Little West 12th Street",
"Livingston Street",
"Lorillard Snuff Mill",
"Lorimer Street",
"Louis Street",
"Love Lane",
"Macdonough Street",
"Macdougal Alley",
"Macdougal Street",
"Macon Street",
"Madison Avenue",
"Madison Street",
"Maiden Lane",
"Main Street",
"Malcolm X Boulevard",
"Manhattan Avenue",
"Maple Street",
"Marcus Garvey Boulevard",
"Marcus Garvey Park",
"Marcy Avenue",
"Marlborough Road",
"Maujer Street",
"Mcdonald Avenue",
"Mercer Street",
"Middagh Street",
"Midwood Street",
"Milligan Place",
"Milton Avenue",
"Milton Street",
"Mitchell Place",
"Monroe Place",
"Montague Street",
"Montague Terrace",
"Montgomery Place",
"Morris Avenue",
"Morris Park Avenue",
"Morton Street",
"Mott Street",
"Mount Morris Park West",
"Mulry Square",
"Murray Street",
"Narrows Avenue",
"Nassau Street",
"Nevins Street",
"New Dorp Lane",
"New Lots Avenue",
"Newkirk Avenue",
"Nixon Avenue",
"Noble Street",
"Norfolk Street",
"Norman Avenue",
"North Moore Street",
"Northern Boulevard",
"Nostrand Avenue",
"Nycta Subway Entrance",
"Oak Street",
"Ocean Avenue",
"Ocean Parkway",
"Ogden Avenue",
"Old Fulton Street",
"Old Slip",
"Oliver Street",
"Orange Street",
"Pacific Street",
"Park Avenue",
"Park Avenue South",
"Park Place",
"Park Row",
"Park Row North",
"Patchin Place",
"Pearl Street",
"Peck Slip",
"Pedestrian Ramps",
"Pell Mansion",
"Perry Street",
"Pierrepont Place",
"Pierrepont Street",
"Pike Street",
"Pineapple Street",
"Plaque",
"Plaques",
"Plaza Street",
"Plaza Street West",
"Polhemus Place",
"Polhemus Street",
"Pomander Walk",
"Poplar Street",
"Powells Cove Boulevard",
"President Street",
"Prince Street",
"Prospect Park West",
"Putnam Avenue",
"Quincy Street",
"Reade Street",
"Recycling Cans",
"Remsen Avenue",
"Remsen Street",
"Revere Place",
"Richmond Hill Road",
"Richmond Road",
"Richmond Street",
"Richmond Terrace",
"Riverdale Avenue",
"Riverside Drive",
"Riverside Drive West",
"Riverside Park",
"Rockefeller Center",
"Rockefeller Plaza",
"Rockland Avenue",
"Rogers Avenue",
"Roosevelt Avenue",
"Roosevelt Island",
"Rufus King Manor",
"Rugby Road",
"Rutherford Place",
"Rutland Road",
"Ryerson Street",
"Sailors' Snug Harbor",
"Schermerhorn Street",
"Sedgwick Avenue",
"Sequine Avenue",
"Sheridan Square",
"Shore Road",
"Sidney Place",
"Simpson Street",
"Smith Street",
"Sniffen Court",
"Snug Harbor",
"Snug Harbor Cultural Center",
"Snyder Avenue",
"South 9th Street",
"South Elliott Place",
"South Oxford Street",
"South Portland Avenue",
"South Portland Street",
"South Street",
"South Street Seaport",
"South William Street",
"Southern Boulevard",
"Spring Street",
"St. Alban's Place",
"St. Andrew's Plaza",
"St. Ann's Avenue",
"St. Felix Street",
"St. James Place",
"St. Johns Place",
"St. John's Place",
"St. Lukes Place",
"St. Luke's Place",
"St. Mark Avenue",
"St. Marks Avenue",
"St. Marks Place",
"St. Mark's Place",
"St. Nicholas Avenue",
"St. Nicholas Terrace",
"St. Patrick's Place",
"St. Paul's Avenue",
"State Street",
"Sterling Place",
"Sterling Street",
"Stone Street",
"Stratford Road",
"Street Signs",
"Strong Place",
"Stuyvesant Avenue",
"Stuyvesant Square",
"Stuyvesant Street",
"Sullivan Street",
"Sutphin Boulevard",
"Sutton Place",
"Sycamore Avenue",
"Sylvan Terrace",
"Thomas Street",
"Thompson Street",
"Throop Avenue",
"Times Square",
"Tompkins Avenue",
"Tompkins Place",
"Trinity Place",
"Tudor City",
"Tudor City Place",
"Union Hall Street",
"Union Square West",
"Union Street",
"University Place",
"Van Cortlandt Mansion",
"Vandam Street",
"Vanderbilt Avenue",
"Varick Street",
"Verandah Place",
"Verdi Square",
"Vernon Boulevard",
"Vesey Street",
"Vestry Street",
"Village Road South",
"Walker Street",
"Wall Street",
"Warren Place",
"Warren Street",
"Warsoff Place",
"Washington Avenue",
"Washington Mews",
"Washington Place",
"Washington Square North",
"Washington Square South",
"Washington Square West",
"Washington Street",
"Water Street",
"Watts Street",
"Wave Hill",
"Waverly Avenue",
"Waverly Place",
"Webster Avenue",
"Weirfield Street",
"West 101st Street",
"West 102nd Street",
"West 105th Street",
"West 106th Street",
"West 107th Street",
"West 108th Street",
"West 109th Street",
"West 10th Street",
"West 114th Street",
"West 115th Street",
"West 119th Street",
"West 11th Street",
"West 120th Street",
"West 121st Street",
"West 122nd Street",
"West 123rd Street",
"West 125th Street",
"West 126th Street",
"West 127th Street",
"West 128th Street",
"West 129th Street",
"West 12th Street",
"West 130th Street",
"West 134th Street",
"West 135th Street",
"West 138th Street",
"West 139th Street",
"West 13th Street",
"West 140th Street",
"West 141st Street",
"West 142nd Street",
"West 143rd Street",
"West 144th Street",
"West 145th Street",
"West 148th Street",
"West 14th Street",
"West 150th Street",
"West 151st Street",
"West 155th Street",
"West 156th Street",
"West 160th Street",
"West 162nd Street",
"West 16th Street",
"West 17th Street",
"West 18th Street",
"West 19th Street",
"West 20th Street",
"West 21st Street",
"West 22nd Street",
"West 23rd Street",
"West 247th Street",
"West 249th Street",
"West 24th Street",
"West 252nd Street",
"West 25th Street",
"West 261st Street",
"West 26th Street",
"West 27th Street",
"West 29th Street",
"West 31st Street",
"West 33rd Street",
"West 34th Street",
"West 37th Street",
"West 3rd Street",
"West 40th Street",
"West 41st Street",
"West 42nd Street",
"West 43rd Street",
"West 44th Street",
"West 45th Street",
"West 46th Street",
"West 47th Street",
"West 48th Street",
"West 49th Street",
"West 4th Street",
"West 50th Street",
"West 51st Street",
"West 52nd Street",
"West 53rd Street",
"West 54th Street",
"West 55th Street",
"West 56th Street",
"West 57th Street",
"West 58th Street",
"West 59th Street",
"West 5th Street",
"West 61st Street",
"West 63rd Street",
"West 64th Street",
"West 65th Street",
"West 66th Street",
"West 67th Street",
"West 68th Street",
"West 69th Street",
"West 70th Street",
"West 71st Street",
"West 72nd Street",
"West 73rd Street",
"West 74th Street",
"West 75th Street",
"West 76th Street",
"West 77th Street",
"West 78th Street",
"West 79th Street",
"West 80th Street",
"West 81st Street",
"West 82nd Street",
"West 83rd Street",
"West 84th Street",
"West 85th Street",
"West 86th Street",
"West 87th Street",
"West 88th Street",
"West 89th Street",
"West 8lst Street",
"West 8th Street",
"West 90th Street",
"West 91st Street",
"West 92nd Street",
"West 93rd Street",
"West 94th Street",
"West 95th Street",
"West 96th Street",
"West 9th Street",
"West Broadway",
"West Drive",
"West End Avenue",
"West Houston Street",
"West Kingsbridge Road",
"West Street",
"Westervelt Avenue",
"Westminster Road",
"White Street",
"William Street",
"Willoughby Avenue",
"Willoughby Street",
"Willow Place",
"Willow Street",
"Wilson Avenue",
"Winant Place",
"Woodrow Road",
"Woodycrest Avenue",
"Wooster Street",
"Worth Street",
"Wyckoff Street",
"York Avenue"
};
#endregion Data Generation
public static string Street()
{
return Streets[Generator.Next(0, Streets.Count - 1)];
}
public static string City()
{
return Cities[Generator.Next(0, Cities.Count - 1)];
}
public static string StateName()
{
return States[Generator.Next(0, States.Count - 1)].StateName;
}
public static string StateCode()
{
return States[Generator.Next(0, States.Count - 1)].StateCode;
}
public static string Zip()
{
return Zip(false);
}
public static string Zip(bool withExtension)
{
var address = States[Generator.Next(0, States.Count - 1)];
return Zip(withExtension, address.ZipRangeBegin, address.ZipRangeEnd);
}
private static string Zip(bool withExtension, int zipRangeBegin, int zipRangeEnd)
{
var zip = Generator.Next(zipRangeBegin, zipRangeEnd);
var pre = string.Format("{0:d5}", zip);
if (!withExtension) return pre;
var post = Zip(false);
return string.Format("{0}-{1}", pre, post.Substring(0, 4));
}
public static string FullAddress()
{
return FullAddress(false);
}
public static string FullAddress(bool withExtension)
{
var address = States[Generator.Next(0, States.Count - 1)];
return string.Format("{0} {1}, {2}, {3} {4}",
Generator.Next(1, 10000),
Street(),
City(),
address.StateName,
Zip(withExtension, address.ZipRangeBegin, address.ZipRangeEnd));
}
public static string PhoneNumber()
{
return GetRandom.Usa.PhoneNumber();
}
public static string SocialSecurityNumber()
{
return GetRandom.Usa.SocialSecurityNumber();
}
internal class UsAddressFake
{
internal string StateName { get; set; }
internal string StateCode { get; set; }
internal int ZipRangeBegin { get; set; }
internal int ZipRangeEnd { get; set; }
}
}
}
</pre></div>You can use this class in your project, or create a separate project and add the class to the project and import the project reference into you project containing your DbContext class.<br />
<br />
Let’s say that you’ve created a Visual Studio solution with an <a href="http://www.asp.net/mvc">ASP.NET MVC 3</a> application, <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> and using <a href="http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/">MvcScaffolding</a> – similar to Steve Sanderson’s Mix 11 cast: <a href="http://channel9.msdn.com/events/MIX/MIX11/FRM13">Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More</a>. Your MVC 3 project contains the following two Model classes and DbContext classs:<br />
<br />
<div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.Collections.Generic;
namespace MvcCodeFirstSqlCompact.Models
{
public class Dinner
{
public int DinnerId { get; set; }
public string Title { get; set; }
public DateTime EventDate { get; set; }
public string Address { get; set; }
public string HostedBy { get; set; }
public string UrlLink { get; set; }
public virtual ICollection<Rsvp> Rsvps { get; set; }
}
}
namespace MvcCodeFirstSqlCompact.Models
{
public class Rsvp
{
public int RsvpId { get; set; }
public string AttendeeEmail { get; set; }
public int DinnerId { get; set; }
public virtual Dinner Dinner { get; set; }
}
}
namespace MvcCodeFirstSqlCompact.Models
{
public class MvcCodeFirstSqlCompactContext : DbContext
{
public MvcCodeFirstSqlCompactContext()
{
Database.SetInitializer(new MvcCodeFirstSqlCompactInitializer());
}
public DbSet<MvcCodeFirstSqlCompact.Models.Dinner> Dinners { get; set; }
public DbSet<MvcCodeFirstSqlCompact.Models.Rsvp> Rsvps { get; set; }
}
}
</pre></div>Notice how the DbContext constructor sets the initializer to MvcCodeFirstSqlCompactInitializer. This is the class that will insert data into your data source once a change in made to one of your model classes and requires database tables to be dropped. The following snippet is the code for the MvcCodeFirstSqlCompactInitializer:<br />
<br />
<div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.Data.Entity;
using FizzWare.NBuilder;
using FizzWare.NBuilder.Generators;
namespace MvcCodeFirstSqlCompact.Models
{
public class MvcCodeFirstSqlCompactInitializer : DropCreateDatabaseIfModelChanges<MvcCodeFirstSqlCompactContext>
{
protected override void Seed(MvcCodeFirstSqlCompactContext context)
{
var uniqueGenerator = new UniqueRandomGenerator();
var generator = new RandomGenerator();
var dinners = Builder<Dinner>.CreateListOfSize(10).WhereAll()
.Have(d => d.Title = string.Format("{0} {1} Dinner", uniqueGenerator.Next(0, 100), GetRandom.UK.County()))
.And(d => d.Address = UsAddressRandomizer.FullAddress(true))
.And(d => d.HostedBy = string.Format("{0} {1}", GetRandom.FirstName(), GetRandom.LastName()))
.And(d => d.EventDate = uniqueGenerator.Next(new DateTime(2010, 1, 1), new DateTime(2011, 5, 4)))
.And(d => d.UrlLink = "http://" + GetRandom.Url())
.Build();
foreach (var dinner in dinners)
context.Dinners.Add(dinner);
var rsvps = Builder<Rsvp>.CreateListOfSize(300).WhereAll()
.Have(d => d.AttendeeEmail = GetRandom.Email())
.And(d => d.Dinner = dinners[generator.Next(1, 10)])
.Build();
foreach (var rsvp in rsvps)
context.Rsvps.Add(rsvp);
}
}
}
</pre></div>Notice how this class derives from DropCreateDatabaseIfModelChanges<T>, where T is your DbContext class? This class will execute the code in the overridden the Seed method when <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> needs to create OR recreate the data source. In the above scenario, the Seed method uses the <a href="http://nbuilder.org/">NBuilder</a> and UsAddressRandomizer facilities to generate data and insert the data into your data tables. <br />
<br />
No more manual data insertions into your database once <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> creates/recreates the database. Not as sweet as EF Code First combined with MvcScaffolding, but pretty sweet nonetheless?<br />
<br />
All pains aside, I’m really impressed with <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a> and liking it more and more everyday. That said, I hope this post and <a href="http://nbuilder.org/">NBuilder</a> helps your avoid some of the pain associated with <a href="http://msdn.microsoft.com/en-us/data/aa937723">EF Code First</a>.<br />
<br />
Again, if you are unfamiliar with any of the previous concepts and technologies, I highly recommend that you take a look at Steve Sanderson’s Mix 11 cast - <a href="http://channel9.msdn.com/events/MIX/MIX11/FRM13">Scaffolding – ASP.NET, NuGet, Entity Framework Code First and More</a>, his blog series - <a href="http://blog.stevensanderson.com/2011/01/13/scaffold-your-aspnet-mvc-3-project-with-the-mvcscaffolding-package/">Scaffold your ASP.NET MVC 3 project with the MvcScaffolding package</a>, and explore the usefulness of <a href="http://nbuilder.org/">NBuilder</a>.<br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-84702538516672257742011-03-22T10:24:00.000-04:002011-03-22T10:24:57.012-04:00Updated - MvcContrib UI Extensions - Themed Grid & MenuAfter a comment on by blog <a href="http://tdryan.blogspot.com/2011/02/mvccontrib-menu.html" target="_blank">here</a>, I have updated the MvcContrib UI Extensions source code, the sample MVC3 Web application (both source and demo), and deployed a new NuGet package to the public NuGet feed. Here are the links:<br />
<ul><li><a href="http://mvcxgridmenu.codeplex.com/" target="_blank">MvcContrib UI Extensions - Themed Grid & Menu</a></li>
<li><a href="http://tdanryan.com/mvccontrib/" target="_blank">Demo Web Application</a></li>
<li><a href="http://nuget.org/Packages/Search?packageType=Packages&searchCategory=All+Categories&searchTerm=mvccontrib.shp" target="_blank">NuGet Package</a></li>
</ul><div>Thanks for reading...</div>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com7tag:blogger.com,1999:blog-2933401848965498544.post-71346248651127766972011-03-15T07:43:00.005-04:002011-03-15T07:55:37.485-04:00Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 4: ASP.NET MVC 3 ProjectThis is Part 4 in a series of posts that walk through the process of implementing a solution that separates concerns into specific behaviors using the <a href="http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx" target="_blank">Entity Framework</a> 4 and the <a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank">Repository</a> and <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank">Unit of Work</a> Patterns.<br />
<br />
Below is the series outline; again, this is Part 4.<br />
<ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository.html">Part 1: Setup</a><br />
<ul><li>This post involves downloading and creating the SQL Server database, setting up the Visual Studio solution and project structure, and generating the out-of-the-box Entity Framework (EF/EF4) data model from the newly created database.</li>
</ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_15.html">Part 2: Creating the Repositories and Unit of Work (UoW)</a><br />
<ul><li>This is the meat of the series. This post includes downloading some T4 templates, settings a few parameters, and generating the Repositories and Unit of Work (UoW) using the T4 templates and EF4 data model.</li>
</ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_5988.html">Part 3: Review Some of The Generated Code</a><br />
<ul><li>This post will review a few of the generated class/interfaces that the T4 code generation created. </li>
</ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_816.html">Part 4: Using EF, Repository & UoW in an ASP.NET MVC 3 Project</a><br />
<ul><li>This post includes wiring up the EF4 data model, repositories, and UoW to <a href="http://structuremap.net/structuremap/" target="_blank">StructureMap</a> dependency injection container and use of these products in an ASP.NET MVC 3 Web application project.</li>
</ul></li><br />
</ul>Now on to Part 4… Open up the Chinook solution in Visual Studio. Let’s do a little solution organization. Create the following three solution folders by right-clicking the solution file, selecting ‘Add,’ and then selecting ‘New Solution Folder.’ <a href="http://lh5.ggpht.com/_fCDAga0oaOc/TX9QyePgtyI/AAAAAAAABK0/D2YE9TiqW_c/s1600-h/image7.png" style="display: block;"><img alt="image" border="0" height="168" src="http://lh6.ggpht.com/_fCDAga0oaOc/TX9QymPAzNI/AAAAAAAABK4/HTJk_UeQGQQ/image_thumb3.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="591" /></a> <ul><li>Core<br />
</li>
<li>Infrastructure<br />
</li>
<li>Web</li>
</ul>Place the Chinook.Core project into the Core Solution Folder and place the other two projects (Chinook.Data.EF and Chinook.Infrastructure) into the Infrastructure Solution Folder. The Web Solution Folder will contain our MVC Web application project. Let’s do that now… Right-click the Web Solution Folder. Click 'Add’ –> ‘New Project…’ <a href="http://lh3.ggpht.com/_fCDAga0oaOc/TX9Qy9PQtbI/AAAAAAAABK8/naOhH8nbML8/s1600-h/image11.png" style="display: block;"><img alt="image" border="0" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuawmDaUnFgno3c6vOoEY-kWxDcXb0q2mBRw1QyUJGPkCWxF_tqsl0F_4i2B08dJxji5ZF3XuOBM4A_HjNMp4ZLJT7bF-yK2DUqcisLDgS3-VK9lMbqjM0PeuZltG4PnEp9RCmae_SPbfE/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="557" /></a> Next, create an ASP.NET MVC 3 Web Application and name is ‘Chinook.Web’ and click ‘OK.’ <a href="http://lh3.ggpht.com/_fCDAga0oaOc/TX9QzFYjEYI/AAAAAAAABLE/ct7_xgu6fXg/s1600-h/image16.png" style="display: block;"><img alt="image" border="0" height="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjR3i11nzYtrmo2zWpYqEXyN9e8O0CHqJs-AgQYidJsVYucv5_jDLBm-qEDRErO89Hmv96Qn2JN7I0daBHHENk0sZr71738eCykGCXIOqYZrDdh9-KZ0JA5oas86hKhhooCueVOJbYL_dh/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="559" /></a> On the next screen, select ‘Internet Application,’ the ‘Razor’ View engine, and click ‘OK’ <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0covpeI0E0RzpBYa3z_BmZvQ-ZnP31ZvdRoV3v3_b4gb52ROxvJoRfKWLCoY_S9n8LaZoy5FZqgAfwEPQEHcTRUtTlMmfGzHc_UMT13fHSTbaKG5bXwbhxG6VmLXc_rCS3UHpKaITMeR4/s1600-h/image21.png" style="display: block;"><img alt="image" border="0" height="499" src="http://lh4.ggpht.com/_fCDAga0oaOc/TX9Qz4vVOwI/AAAAAAAABLQ/9kgULYDs07k/image_thumb11.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="539" /></a> Right-click the new ‘Chinook.Web’ Application Project and select ‘Set As Startup Project.’ The solution structure should now look similar to the following: <a href="http://lh3.ggpht.com/_fCDAga0oaOc/TX9Q0SwKUmI/AAAAAAAABLU/N3qtucNfKMU/s1600-h/image24.png" style="display: block;"><img alt="image" border="0" height="167" src="http://lh5.ggpht.com/_fCDAga0oaOc/TX9Q0f4APQI/AAAAAAAABLY/Gp8zWRrRHd4/image_thumb12.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="224" /></a> Add the following References to the ‘Chinook.Web’ Project and then build the solution. <a href="http://lh5.ggpht.com/_fCDAga0oaOc/TX9Q06H64mI/AAAAAAAABLc/bATSaQ8yznk/s1600-h/image32.png" style="display: block;"><img alt="image" border="0" height="371" src="http://lh5.ggpht.com/_fCDAga0oaOc/TX9Q1EtpRfI/AAAAAAAABLg/gjirdfp_QvA/image_thumb16.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="565" /></a> In the description of this post, it states that we are going to use StructureMpa as our DI container. We are going to get StructureMap via NuGet. Assuming you have NuGet installed, select the Chinook.Web project, open the ‘Package Manager Console,’ and type the following command: <div style="font-size: 11px;"><pre class="brush: ps">PM> Install-Package StructureMap
</pre></div>This will install StructureMap and register any assemblies with the Chinook.Web project. Once the NuGet command is executed, the NuGet Package Manager Console should echo the following: <a href="http://lh3.ggpht.com/_fCDAga0oaOc/TX9Q1RvWLoI/AAAAAAAABLk/L7FJhpcHY5Y/s1600-h/image36.png" style="display: block;"><img alt="image" border="0" height="78" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNcULE_pU5lS4VdHFxxn2OMXRV-2G_p1FCIO1bidyuvB26jhdvhnfIX192kJAOoeeGYlsjtHhseKF0zVmSFgogNRR2-AdN3hicUq8objE1Y_L6x8gjAju5lOle4Y0GcFg-9c2HAz9AL7Og/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="406" /></a> Go ahead and build the solution. Next, add the the new StructureMap reference to both the Chinook.Data.EF and Chinook.Infrastructure projects and rebuild the solution. Again, this series assumes that you have all the necessary tools (NuGet, POCO templates, etc…) installed with Visual Studio and that you are somewhat familiar with StructureMap. Now, remember the two files (EFRepositoryRegistry.cs.txt and ServicesRegistry.cs.txt) that the T4 templates generated for us in the previous post? We are going to use those files to create our StructureMap registries. The best way to do this is to create two new cs files in the respective projects, copy the code from the generated file, and paste it into these new code files. I understand this is not idea (copy, paste, etc…); however, I didn’t want to limit our solution to StructureMap only, so we’ll just have to deal with the awkwardness for now. So, create the following files and replace all the code in the new code file with the code in the associated generated file. <ul><li>EFRepositoryRegistry.cs – in the Chinook.Data.EF project <br />
<ul><li>EFRepositoryRegistry.cs.txt – generated file</li>
</ul></li>
<li>ServicesRegistry.cs – in the Services directory within the Chinook.Implementation project <br />
<ul><li>ServicesRegistry.cs.txt – generated file</li>
</ul></li>
</ul>Go ahead and build the solution again. Next, we are going to register our repositories, unit of work, and other dependencies (created earlier in a previous post) with StructureMap in our Chinook.Web project. To do this, we are going to use ASP.NET MVC 3 IDependencyResolver – you can read about IDependencyResolver <a href="http://bradwilson.typepad.com/blog/2010/10/service-location-pt5-idependencyresolver.html" target="_blank">here</a> and read the API docs <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.idependencyresolver(v=vs.98).aspx" target="_blank">here</a>. Create a ‘Bootstrap’ directory in the Chinook.Web project and create the following two empty code/class files: <ul><li>StructureMapContainerSetup.cs – make this class static <br />
</li>
<li>StructureMapDependencyResolver.cs</li>
</ul>Now we are going to register the Registries created earlier in these ‘bootstrap’ files. Since this series of posts is walk through on the process of setting up a solution for separation of concerns and not on the theory of such topics, the exercise of explaining the StructureMap registration is beyond the scope of this series. Populate these newly created code files with the following content: <h5>StructureMapDependencyResolver</h5><div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StructureMap;
namespace Chinook.Web.Bootstrap
{
public class StructureMapDependencyResolver : IDependencyResolver
{
private readonly IContainer _container;
public StructureMapDependencyResolver(IContainer container)
{
_container = container;
}
#region Implementation of IDependencyResolver
/// <summary>
/// Resolves singly registered services that support arbitrary object creation.
/// </summary>
/// <returns>
/// The requested service or object.
/// </returns>
/// <param name="serviceType">The type of the requested service or object.</param>
public object GetService(Type serviceType)
{
var instance = _container.TryGetInstance(serviceType);
if ((instance == null) && !serviceType.IsAbstract)
{
_container.Configure(c => c.AddType(serviceType, serviceType));
instance = _container.TryGetInstance(serviceType);
}
return instance;
}
/// <summary>
/// Resolves multiply registered services.
/// </summary>
/// <returns>
/// The requested services.
/// </returns>
/// <param name="serviceType">The type of the requested services.</param>
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType).Cast<object>();
}
#endregion
}
}
</pre></div><h5>StructureMapContainerSetup</h5><div style="font-size: 11px;"><pre class="brush: csharp">using System.Web.Mvc;
using Chinook.Data.EF;
using Chinook.Infrastructure.Services;
using StructureMap;
namespace Chinook.Web.Bootstrap
{
public static class StructureMapContainerSetup
{
public static void Setup()
{
IContainer container = new Container(
x =>
{
x.AddRegistry(new EFRepositoryRegistry());
x.AddRegistry(new ServicesRegistry());
}
);
DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
}
}
}
</pre></div>Now we are going to invoke the StructureMap registration bootstrapping code from the Application_Start method of the Global.asax.cs file. Here’s the snippet: <div style="font-size: 11px;"><pre class="brush: csharp">protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
StructureMapContainerSetup.Setup();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
</pre></div>Go ahead and build the solution again… We are now going to create a quick controller, view, and some supporting <a href="http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx" target="_blank">View Models</a> that will give a simple example how to use all the code created in this series of posts. For this part, go ahead and download the <a href="http://tdryan.codeplex.com/releases/view/62617">final solution</a>. Logically representing the code here will be difficult and would provide little value without context; therefore, download the <a href="http://tdryan.codeplex.com/releases/view/62617">final solution</a> and review the code in the Chinook.Web project. Here’s a quick list of the steps involved to generated the code samples: <ol><li>Create a ViewModel - AlbumGridItemViewModel. <br />
</li>
<li>Create a IViewModelBuilder/ViewModelBuilder – IAlbumGridItemViewModelBuilder/AlbumGridItemViewModelBuilder. <br />
</li>
<li>Create a new Controller - AlbumController. <br />
</li>
<li>Use constructor injection to inject the ViewModelBuilder into the Controller - IAlbumGridItemViewModelBuilder into the AlbumController. <br />
</li>
<li>Create a View to represent a list of ViewModel items – Index – this is only a list of items; however, the process remains the same for all types of views. <br />
</li>
<li>Register the IViewModelBuilder/ViewModelBuilder with StructureMap – using a similar pattern as the other DI registrations – a StructureMap Registry.</li>
</ol>The resulting list generated in the sample code is not designed for performance (e.g. no paging, sorting, etc..). In production, this type of code can and should be refactored. That said, the key points throughout this series are the patterns used to create a solution based on separation of concerns – including the Repository and Unit of Work patterns and using StructureMap as a Dependency Injection container.<br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com20tag:blogger.com,1999:blog-2933401848965498544.post-82985405767477534762011-03-15T07:17:00.005-04:002011-03-15T07:53:41.929-04:00Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 3: Generated Code ReviewThis is Part 3 in a series of posts that walk through the process of implementing a solution that separates concerns into specific behaviors using the <a href="http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx" target="_blank">Entity Framework</a> 4 and the <a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank">Repository</a> and <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank">Unit of Work</a> Patterns.<br />
<br />
Below is the series outline; again, this is Part 3.<br />
<ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository.html">Part 1: Setup</a><br />
<ul><li>This post involves downloading and creating the SQL Server database, setting up the Visual Studio solution and project structure, and generating the out-of-the-box Entity Framework (EF/EF4) data model from the newly created database.</li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_15.html">Part 2: Creating the Repositories and Unit of Work (UoW)</a><br />
<ul><li>This is the meat of the series. This post includes downloading some T4 templates, settings a few parameters, and generating the Repositories and Unit of Work (UoW) using the T4 templates and EF4 data model.</li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_5988.html">Part 3: Review Some of The Generated Code</a><br />
<ul><li>This post will review a few of the generated class/interfaces that the T4 code generation created. </li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_816.html">Part 4: Using EF, Repository & UoW in an ASP.NET MVC 3 Project</a><br />
<ul><li>This post includes wiring up the EF4 data model, repositories, and UoW to <a href="http://structuremap.net/structuremap/" target="_blank">StructureMap</a> dependency injection container and use of these products in an ASP.NET MVC 3 Web application project.</li></ul></li></ul>Now on to Part 3… Open up the Chinook solution in Visual Studio. Expand the Chinook.Core Project, expand the Domain directory, and then expand both the Domain.Poco.tt and Domain.Poco.Metadata.tt files. You should see something like the following: <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-Cw0DPiYXQT31fEHCukq_2EUL5RTMhL-cEQFRiDtk8ArI02S7D3i7-ZmMYLe1Qj6OGfG1Ip3J1ODTSpUQkiTR3-9Zy60ZfC1sCynG9lw0Gi3dXujB3Wcx-ybykfBsutef11VPhCv1uTfP/s1600-h/image15.png" style="display: block;"><img alt="image" border="0" height="413" src="http://lh3.ggpht.com/_fCDAga0oaOc/TX9Kpw88RtI/AAAAAAAABKM/hCd_6a-xxHw/image_thumb9.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="246" /></a> These child-files under the *.tt file are the code file generated by the T4 templates. Go ahead an open the highlighted file – InvoiceLine.Metadata.cs and this file’s sister class file Invoice.cs (under the Domain.Poco.tt file). The Invoice.cs file contains a POCO class for the Invoice entity of the EF data model (edmx), while the InvoiceLine.Metadata.cs contains the data annotations/metadata ‘buddy’ class for the sister POCO class (Invoice.cs). That’s quite a mouthful, so take a bit of time and review the generated code. Okay, now expand the Domain and Services directories and the associated T4 template files within the Chinook.Core project. You should have something similar to the following: <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrOnQr9fQxag8EGe9zfvyC1uzH5aTY-UCUcsI2Icdd927vhp3WCK4UM_8finTT1MRBsz4uRaWzSUiYS1U7jpkQ3hwHMHD7brBZJGh16Z2zcv-DNtdyIER45u9qijt679DFt8q_Uj7JwVqk/s1600-h/image14.png" style="display: block;"><img alt="image" border="0" height="495" src="http://lh4.ggpht.com/_fCDAga0oaOc/TX9KqNboH_I/AAAAAAAABKU/zlBhgY41oVk/image_thumb8.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="246" /></a> Open up the following Repository.Interface.tt child files. Reference the code snippets below when reading the brief description of each file.
<ul><li>IReadOnlyRepository.cs <ul><li>The IReadOnlyRepository is the base interface that all the entity specific interfaces inherit from. The IReadOnlyRepository contains (you guessed it…<img alt="Winking smile" class="wlEmoticon wlEmoticon-winkingsmile" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisjBolsZ3jt8PWVHp73v3hXvkhxqC6njFLOpe3d4Y3fo4VM4cTNwUrRJc0WOR5q6RbF-9xgt5Co1HGBkczlwZpKpgmcFsXGOwAXzWOjpWyuRBVaoKR5cnWR0eBReJo709J1OxkwywPpGe_/?imgmax=800" style="border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none;" />) read-only interfaces to the persistence layer.</li>
</ul></li>
<li>IRepository.cs <ul><li>The IRepository interface extends the IReadOnlyIRepository interface to include creating and deleting or entities.<br />
</li>
<li>The original intent of separating the IReadOnlyRepository and IRepository interfaces was that so POCO object backed by data views (VIEWs on a database) would not inherit creating and deleting functionality.</li>
</ul></li>
<li>IUnitOfWork.cs <ul><li>The IUnitOfWork interface handles all the transactions and changes needed to persist modifications to the persistence mechanism.<span class="Apple-style-span" style="font-weight: bold;"> </span></li>
</ul></li>
</ul><h4>IReadOnlyRepository.cs</h4><div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace Chinook.Core.Repository
{
/// <summary>
/// Generic Read-Only Repository Contract
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IReadOnlyRepository<t> where T : class
{
/// <summary>
/// Gets an IQueryable sequence of entities of type T.
/// </summary>
/// <returns></returns>
IQueryable<t> Queryable();
/// <summary>
/// Gets an IEnumerable sequence of all entites of type T.
/// </summary>
/// <returns></returns>
IEnumerable<t> All();
/// <summary>
/// Get an IEnumerable sequence of entities of type T filtered on the @where predicate.
/// </summary>
/// <param name="where">The where predicate.</param>
/// <returns></returns>
IEnumerable<t> Find(Expression<func><t bool ,>> where);
/// <summary>
/// Gets a single entity in a sequence of entities of type T using the filtered @where predicate.
/// </summary>
/// <param name="where">The where predicate.</param>
/// <returns></returns>
T Single(Expression<func><t bool ,>> where);
/// <summary>
/// Gets the first entity in a sequence of entities of type T using the filtered @where predicate.
/// </summary>
/// <param name="where">The where predicate.</param>
/// <returns></returns>
T First(Expression<func><t bool ,>> where);
/// <summary>
/// Gets a single entity (or default of entity of type T) in a sequence of entities of type T using the filtered @where predicate.
/// </summary>
/// <param name="where">The where predicate.</param>
/// <returns></returns>
T SingleOrDefault(Expression<func><t bool ,>> where);
/// <summary>
/// Gets a first entity (or default entity of type T) in a sequence of entities of type T using the filtered @where predicate.
/// </summary>
/// <param name="where">The where predicate.</param>
/// <returns></returns>
T FirstOrDefault(Expression<func><t bool ,>> where);
}
}</pre></div><h4>IRepository.cs</h4><div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Chinook.Core.Repository
{
/// <summary>
/// Generic Repository Contract.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRepository<t> : IReadOnlyRepository<t> where T : class
{
/// <summary>
/// Adds the specified entity to the respository of type T.
/// </summary>
/// <param name="entity">The entity to add.</param>
void Add(T entity);
/// <summary>
/// Deletes the specified entity to the respository of type T.
/// </summary>
/// <param name="entity">The entity to delete.</param>
void Delete(T entity);
/// <summary>
/// Attaches the specified entity to the respository of type T.
/// </summary>
/// <param name="entity">The entity to attach.</param>
void Attach(T entity);
}
}</pre></div><span class="Apple-style-span" style="font-weight: bold;">IUnitOfWork.cs</span>
<div style="font-size: 11px;"><pre class="brush: csharp">namespace Chinook.Core.Repository
{
/// <summary>
/// Unit of Work Contract
/// </summary>
public interface IUnitOfWork
{
/// <summary>
/// Commits the changes to the data store.
/// </summary>
void Commit();
}
}
</pre></div>
The other Repository interfaces are just POCO specific Repository interfaces – man, that sounds really redundant…
The Services Interfaces – child-files of the Services.Interface.tt template are just empty service interfaces that you can add to as needed. Like the Repository interfaces, each POCO has it’s own Service interface.
Next, expand the Chinook.Infrastructure Project’s Services.Implementation.tt file. The code files generated by this T4 template are concrete implementation class of the aforementioned Service interfaces. There is a one-to-one relationship among the code generated interfaces to the code generated concrete implementations.
Next, expand the Chinook.Data.EF Project’s Repository.Implementation.EF.tt file.
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXQtfTfAyXRBgQCzx4w21XrlVDYfrB8_HWO35ZPHaPdv2pUZYJ6B8G9s7yocLbAw4_otfXNr871JVelumThNBmYDLfSJeHJTwVOiALmJJ8vR3jlSmu9Sa7rGpuUuwoQ_LqDdfnpsKaLSvF/s1600-h/image19.png" style="display: block;"><img alt="image" border="0" height="458" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg66y30Y8UoufnzbWgZag8uDcjPNQOWhkurPU2O2uormqj61Nui330uKvBhxXwhZ4tZBVyU40mXfIzcFPd5SNLmwkBAtlSWgcPLDPHjE3EUnTsFf3mjCKdF4czC_uJy8eTuaWwRxAz2gkWF/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="369" /></a>
As you can see, there is pretty much a one-one-relationship among the interfaces generated in the Chinook.Core/Repository to the concrete implementations here. Go ahead and spend some time looking over the generated files. The implementation for each is straight forward.
Beyond the Repository implementations, the following are notable files generated by the Repository.Implementation.EF.tt template:
<ul><li>IObjectContext <br />
<ul><li>this is an interface that defines the contract used by the ObjectContextAdapter, the EFUnitOfWork, and ultimately the ObjectContext.</li>
</ul></li>
<li>ObjectContextAdapter <br />
<ul><li>this is a simple <a href="http://en.wikipedia.org/wiki/Adapter_pattern" target="_blank">adapter</a> class that wraps the Entity Framework’s ObjectContext object for use in the Repository/Unit of Work paradigm. This class implements the IObjectContext contract.</li>
</ul></li>
<li>RepositoryIQueryableExtensions <br />
<ul><li>this class includes a single method: Include. Include is an IQueryable(of T) extension method that affords the ‘Eager Loading’ functionality provided by the Entity Framework. But, since our solution abstracts the Entity Framework, the EF ‘Eager Loading’ Include method is not available. This extension method gives our solution the functionality back. You may not realize this yet, but that is a really cool ‘feature!’ <br />
</li>
<li>The implementation of this Include extension method was taken from the following article on MSDN: <a href="http://msdn.microsoft.com/en-us/ff714955.aspx">http://msdn.microsoft.com/en-us/ff714955.aspx</a> – this is a great article and one that I got quite a few ideas for this series and solution.</li>
</ul></li>
</ul><span class="Apple-style-span" style="font-weight: bold;">Template Bonuses</span>
<h5>Template Force Code (Re)Generation – or NOT</h5>Of this six T4 templates included in the <a href="http://tdryan.codeplex.com/releases" target="_blank">download</a>, all but the Domain.Poco.tt contain the following settings:
<div style="font-size: 11px;"><pre class="brush: csharp">// answers the question: Force generation of file even if the code file exists?
bool forceCodeGeneration = false;
</pre></div>
As the name of the setting/variable and the associated comment suggests, this is an on/off switch for forcing code (re)generation. The default for this setting is false, meaning that if code is regenerated, the existing code will NOT be overwritten. So, let’s say that you create a custom email validator like the one in a previous post of mine - <a href="http://tdryan.blogspot.com/2010/12/aspnet-mvc-3-custom-validation.html" target="_blank">ASP.NET 3 Custom Validation</a>. You manually decorate a few POCO properties in the POCO ‘buddy’ classes – the one containing metadata and data annotations – with the new email validator (e.g. Required(ErrorMessage = “Email is Required”)]. You have client-side and server-side validation working like a charm. Now, let’s say that your one or your database tables has changed and or you added a new table. You are going to want to regenerate all the classes and interfaces that the T4 templates created for you. No Problem! If you have the forceCodeGeneration settings set to false, your manual code changes will NOT get overwrittenand that hard work of yours will not need to be redone, or at a minimum, merged from the files in you source control system. You are using a source control system, aren’t you???
<h5>StructureMap configuration for Repositories and Services</h5>If you’re reading this blog series, I’m sure you’re familiar with <a href="http://en.wikipedia.org/wiki/Dependency_injection" target="_blank">Dependency Injection</a> (DI). There are quite a few DI containers for .NET; however, my favorite is <a href="http://structuremap.net/structuremap/" target="_blank">StructureMap</a>. Why is it my favorite? Well, when I first endeavored on the DI/<a href="http://en.wikipedia.org/wiki/Inversion_of_control" target="_blank">IOC</a> concept, StructureMap is what those around me recommended. I was not disappointed! The documentation could be better – it’s a little out-of-date; however, the DI API for StructureMap is extremely easy to use and relatively easy to understand. You will first need to overcome the DI/IOC paradigm challenges, but once the 'light goes on,’ you’ll wonder how you survived without it…
Okay, back to the Bonuses… Expand the Repository.Implementation.EF.tt and Service.Implementation.tt T4 templates. Below are screenshots of the two T4 template generated outputs. Notice the highlighted files…
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0IF5-btRJOAQD1zl_daxsjAfLOfruQXyhWiK4rGkMsB_YNxJkq13Hn3PFZmjS5vweQucwlmbiCNXelswNKRM1aIa4iQ2BvhGsYvM0GakaWatOdMmLCtXH0NlR1VYOXHxO2r_iX2EGQ4fU/s1600-h/image46.png" style="display: block;"><img alt="image" border="0" height="139" src="http://lh5.ggpht.com/_fCDAga0oaOc/TX9Krdm8fEI/AAAAAAAABKo/0T13XO3Irbs/image_thumb24.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="316" /></a>
<a href="http://lh5.ggpht.com/_fCDAga0oaOc/TX9KrhqX6zI/AAAAAAAABKs/qRQYtUwjEI0/s1600-h/image42.png" style="display: block;"><img alt="image" border="0" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgekFNhJzYV-xqM2YpIPgqK58jTrPUE8FS63agn4dqYEBA7gsCEqw_crKF7rV2Qqd5fXxZv9KNf6UTen-5p0XrF0lgRLhNYdAkAXRBCrxPmcsUh-e4iQtU9xC1kdgUk35av3Y-grf7Squ_J/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="319" /></a>
All four of these files contain StructureMap Dependency Injection registration code. The files stating with __StructureMap.* contain ‘raw’ registration code that you can use however you’d like. The other two files (EFRepositoryRegistry.cs.txt and ServicesRegistry.cs.txt) contain StructureMap Registry derived classes. According to the <a href="http://structuremap.net/structuremap/RegistryDSL.htm" target="_blank">StructureMap documentation</a>, Registries are the recommended way to configure StructureMap:
<div style="background-color: white; border-bottom: #ccc 1px solid; border-left: #ccc 1px solid; border-right: #ccc 1px solid; border-top: #ccc 1px solid; color: black; font-style: italic; margin: 5px 10px; padding-bottom: 5px; padding-left: 10px; padding-right: 10px; padding-top: 5px;">“The Registry DSL is the recommended way to configure StructureMap, and creating Registry classes is the recommended way of using the Registry DSL.” </div><br />
We will be using the code in these files in the next post in this series… Stay tuned…<br />
<br />
In summary, we reviewed a few of the code files that the T4 templates generated, discussed how to NOT to overwrite your manual code changes to the generated files, and discovered how the T4 templates generate StuctureMap DI registration snippets and Registries for you.<br />
<br />
In the next post in this series, we will put all the fruits of our labor (okay, the code generated labor) to use in an ASP.NET MVC 3 Web Application.<br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com2tag:blogger.com,1999:blog-2933401848965498544.post-66045460887045498912011-03-15T06:53:00.019-04:002011-03-15T07:53:12.930-04:00Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 2: Creating the Repositories and Unit of Work (UoW)This is Part 2 in a series of posts that walk through the process of implementing a solution that separates concerns into specific behaviors using the <a href="http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx" target="_blank">Entity Framework</a> 4 and the <a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank">Repository</a> and <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank">Unit of Work</a> Patterns.<br />
<br />
Below is the series outline; again, this is Part 2.<br />
<ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository.html">Part 1: Setup</a><br />
<ul><li>This post involves downloading and creating the SQL Server database, setting up the Visual Studio solution and project structure, and generating the out-of-the-box Entity Framework (EF/EF4) data model from the newly created database.</li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_15.html">Part 2: Creating the Repositories and Unit of Work (UoW)</a><br />
<ul><li>This is the meat of the series. This post includes downloading some T4 templates, settings a few parameters, and generating the Repositories and Unit of Work (UoW) using the T4 templates and EF4 data model.</li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_5988.html">Part 3: Review Some of The Generated Code</a><br />
<ul><li>This post will review a few of the generated class/interfaces that the T4 code generation created. </li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_816.html">Part 4: Using EF, Repository & UoW in an ASP.NET MVC 3 Project</a><br />
<ul><li>This post includes wiring up the EF4 data model, repositories, and UoW to <a href="http://structuremap.net/structuremap/" target="_blank">StructureMap</a> dependency injection container and use of these products in an ASP.NET MVC 3 Web application project.</li></ul></li></ul>Now on to Part 2… The following <a href="http://tdryan.codeplex.com/releases" target="_blank">download</a> contains some T4 templates that I’ve created and/or modified from other sources. These T4 templates will build all the code necessary to create our Domain Models, Domain Model Metadata (e.g. Data Annotations), Repositories, Services, and Unit of Work all by pointing each related T4 to the EF data model (edmx) created in <a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository.html">Part 1</a> of this series. <a href="http://tdryan.codeplex.com/releases" target="_blank">T4 Templates Download</a>. Go ahead and download the zip file and un-compress the contents into a directory directly under the solution root. The solution’s root directory should look something like the following, where the T4_EF4_Repository directory is the directory that contains the uncompressed files from the download. <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjER2o_v1WNOnql9iWOBGrPz7y7Nw6JIgTuhJk4AoPBugbnLnoIelDMCRNMtONQtv62d7In69D9Z1pBZY96BnFcrPt-sWdLCHMg6qaLbqm8tBEEih0co965BBGdNr1AKO07wTZg7zh-07pM/s1600-h/p2Solutionlist003.png" style="display: block;"><img alt="p2Solutionlist00" border="0" height="157" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp8X5vgzGYEFjR0o8UtrAlCmBS6WGhZlV2gBCsefBAhf1lOaF4M_QVIB2WKbxNVUqhoe7m5VqGkvIaUr-Z4KzJ00I0sIh6IU11AYaSCf_QgT-et9XzRcdZPDC46psU25QIB8Kd_5GWHPqk/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="p2Solutionlist00" width="183" /></a> Open up the T4_EF4_Repository directory. The directory should contain a ‘Source’ directory and a single PowerShell file: <a href="http://lh5.ggpht.com/_fCDAga0oaOc/TX9FAcIUftI/AAAAAAAABI4/Vba3hV18mtQ/s1600-h/image7.png" style="display: block;"><img alt="image" border="0" height="52" src="http://lh6.ggpht.com/_fCDAga0oaOc/TX9FAmpA_oI/AAAAAAAABI8/X7X36-mLqSI/image_thumb3.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="154" /></a> The ‘Source’ directory should contain six T4 template files (*.tt) <a href="http://lh6.ggpht.com/_fCDAga0oaOc/TX9FAnC4wSI/AAAAAAAABJA/twVIJJwZd5Q/s1600-h/image6.png" style="display: block;"><img alt="image" border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoVrJtoBIEFtQzq5aGeEkioOVO30waCjAuOhL6TQ3mbHP_D_70ofgymafgq84-hEuO34KHi0Zc6XyTjL3yY5qlkx7L8CMlbiioGw0KWE31z2nrkNL4HF1miW-iYHy6EQMGqyD7OznXxl3j/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="195" /></a> What are these files? Well, the files with the *.tt extension are the T4 templates that will generate the code, while the single file with the *.ps1 extension is a PowerShell script. The following briefly describes each file:
<ul><li>Domain.Poco.tt <ul><li>This template generates the POCO (Domain) classes from your EF data model.</li>
</ul></li>
<li>Domain.Poco.Metadata.tt <ul><li>This template generates data annotations/metadata ‘buddy’ classes for the POCOs.</li>
</ul></li>
<li>Repository.Interface.tt <ul><li>This template generates all the associated Repository Interfaces/Contracts, including: <ul><li>base IReadOnlyRepository and IRepository Interfaces<br />
</li>
<li>IUnitOfWork Interface<br />
</li>
<li>I<POCO_ClassName>Repository Interface for each POCO class generated from you EF data model.</li>
</ul></li>
</ul></li>
<li>Repository.Implementation.EF.tt <ul><li>This template generates the EF-related concrete class implementations defined by the IRepository Interfaces/Contracts.</li>
</ul></li>
<li>Services.Interface.tt <ul><li>This template generates a light-weight Service Interfaces/Contracts for each POCO class.</li>
</ul></li>
<li>Services.Implementation.tt <ul><li>This template generates the concrete class implementation defined by the Service Interfaces/Contracts.</li>
</ul></li>
<li>prepareT4Templates.ps1 <ul><li>This is just a simple PowerShell script that contains project-specific settings to assist in generation T4 templates specific to the project – in our scenario, the Chinook application solution.</li>
</ul></li>
</ul>Open up the Chinook Visual Studio Solution. We should now have a Visual Studio Solution with thee Projects (Chinook.Core, Chinook.Data.EF, Chinook.Infrastructure) and a directory located at the solution root containing the T4 templates and single PowerShell file. Open up T4_EF4_Repository directory in Windows Explorer. Right-click the PowerShell file and select ‘Edit’ from the context menu. <a href="http://lh3.ggpht.com/_fCDAga0oaOc/TX9FBOgbeJI/AAAAAAAABJI/AZZ9QhqK-N0/s1600-h/image11.png" style="display: block;"><img alt="image" border="0" height="72" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuBJOkdZujOG6wZ3_OLDsCKpf9Lh_tKrPHXFGiJzZwLPGHZB4pC22UEED7pjOM1sIRY-MKGQA7HXztuWnLr-DNFOx5YguKRgafJZhecuQUOcQB3ShEaIZWiPzQ9hF_52mK0umnBio52jlL/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="329" /></a> This will open up the PowerShell editor and display the content of the PowerShell file. As you can see, this is simple script that does a find/replace, creates a new directory, and creates new T4 templates that contain the replaced settings.
<div style="font-size: 11px;"><pre class="brush: powershell">#*****************************************************************
#*****************************************************************
#*********** BEGIN Template Parameters ***************************
#*****************************************************************
# path to the project's edmx data model (entity framework data model)
$edmxFilePath = "..\..\Chinook.Data.Ef\Chinook.edmx"
# the namepace name where the solution's domain models live
$domainModelNamespace = "Chinook.Core.Domain"
# the namespace name where the solution's services will live
$serviceInterfaceNamespace = "Chinook.Core.Services"
# the namespace name where the solution's repository will live
$repositoryInterfaceNamespace = "Chinook.Core.Repository"
#*****************************************************************
#*********** END Template Parameters *****************************
#*****************************************************************
function createDirectory($directory){
New-Item $directory -type directory -force
}
function removeDestinationFile($file){
if(Test-Path $file){ Remove-Item $file }
}
function writeout($file){
$sourceFile = "Source/" + $file
$destinationDirectory = "Solution/"
$destinationFile = $destinationDirectory + $file
createDirectory($destinationDirectory)
removeDestinationFile($destinationFile)
(Get-Content $sourceFile) |
Foreach-Object {$_ -replace "\[\*\*EDMX_FILE_PATH\*\*\]", $edmxFilePath} |
Foreach-Object {$_ -replace "\[\*\*DOMAIN_MODEL_NAMESPACE\*\*\]", $domainModelNamespace} |
Foreach-Object {$_ -replace "\[\*\*SERVICE_INTERFACE_NAMESPACE\*\*]", $serviceInterfaceNamespace} |
Foreach-Object {$_ -replace "\[\*\*REPOSITORY_INTERFACE_NAMESPACE\*\*\]", $repositoryInterfaceNamespace} |
Set-Content $destinationFile
}
$files = @("Domain.Poco.tt", "Domain.Poco.Metadata.tt", "Repository.Interface.tt", "Service.Interface.tt", "Repository.Implementation.EF.tt", "Service.Implementation.tt")
foreach($file in $files){
writeout($file)
}
</pre></div>As I mentioned above, the PowerShell file will generate T4 templates specific to your project. If you followed along in Part 1, these setting variables are taken from the namespaces that we specified in the last step. If you missed it, the following table duplicates our previous efforts:
<table border="0" cellpadding="2" cellspacing="0" style="width: 400px;"><tbody>
<tr> <td valign="top" width="133"><strong><u>Directory</u></strong></td> <td valign="top" width="267"><strong><u>Namespace</u></strong></td></tr>
<tr> <td valign="top" width="133">Domain</td> <td valign="top" width="267">Chinook.Core.Domain</td></tr>
<tr> <td valign="top" width="133">Repository</td> <td valign="top" width="267">Chinook.Core.Repository</td></tr>
<tr> <td valign="top" width="133">Services</td> <td valign="top" width="267">Chinook.Core.Services</td></tr>
</tbody></table>
The following are the project-specific settings:
<ul><li>$edmxFilePath <br />
<ul><li>relative path to the solution’s EF data model (edmx)</li>
</ul><br />
</li>
<li>$domainModelNamespace <br />
<ul><li>the namespace where the solution’s POCO’s live – see namespace table above</li>
</ul></li>
<li>$serviceInterfaceNamespace <br />
<ul><li>the namespace where the solution’s Service Interfaces/Contracts live – see namespace table above</li>
</ul></li>
<li>$repositoryInterfaceNamespace <br />
<ul><li>the namespace where the solution’s Repository Interfaces/Contracts live – see namespace table above</li>
</ul></li>
</ul>If you followed through this post's series, there is no need to change the aforementioned settings. They are already set to the proper solution-specific settings. If not, go ahead and change the necessary settings. You can run the PowerShell file within the editor of by right-clicking the PowerShell file and click ‘Run with PowerShell.’ However, since we already have the file open in the editor, we are going to use the editor. Click the ‘Run’ button on the editor’s toolbar: <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdfGg_KIHZB3Dkk5t8XThPzKgg20g6yE2mk1PASeEVCFjEAHEw9AOcSUto4JPzXOM7GxsLxfRAWJ5sMmselEY-TSm-fqdGQfq4BzA2h7KilFt97Jj4LGpZxcuAfZPwnA7B1nKyBxDzX6Pd/s1600-h/image15.png" style="display: block;"><img alt="image" border="0" height="73" src="http://lh3.ggpht.com/_fCDAga0oaOc/TX9FBrrdTaI/AAAAAAAABJU/UTdaFvly9-E/image_thumb7.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="405" /></a> If when running the PowerShell file you receive the following error, you do not have the proper permission to execute PowerShell scripts:
<div style="color: red; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; padding-top: 10px;">File C:\Chinook\T4_EF4_Repository\prepareT4Templates.ps1 cannot be loaded. The file C:\Chinook\T4_EF4_Repository\prepareT4Templates.ps1 is not digitally signed. The script will not execute on the system. Please see "get-help about_signing" for more details.. </div>You have a couple choices to get around this, but the easiest is to set the PowerShell execution policy to ‘unrestricted’ using the following PowerShell command (* you must be running PowerShell as an Administrator). Go ahead and run this command in the PowerShell console in the bottom pane of the PowerShell editor:
<div style="font-size: 11px;"><pre class="brush: powershell">Set-ExecutionPolicy UnRestricted
</pre></div>Accept the ‘Execution Policy Change’ dialog message – the dialog only appears if you are using the editor. If you are using the non-editor PowerShell console, this ‘Execution Policy Change’ message will only echo to the console. Sorry about that little hiccup. If you’re not comfortable with setting the execution policy to 'unrestricted,’ you get reverse the policy back to ‘restricted’ once you’re done generating the necessary T4 templates by using the following PowerShell command:
<div style="font-size: 11px;"><pre class="brush: powershell">Set-ExecutionPolicy Restricted
</pre></div>For more PowerShell documentation, check out <a href="http://msdn.microsoft.com/en-us/library/ee176961.aspx" target="_blank">MSDN</a>. Close the PowerShell editor. Okay, back to the tutorial… Once you execute the PowerShell script, the T4_EF4_Repository directory will now contain a new ‘Solution’ sub-directory and will contain six T4 templates with the project-specific settings defined earlier. These are the templates that we will be using in our application. <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilv8NLeaefOnwP1ZhzGrBLZAOHRGT3tT2k8dr5G_x7rVJdXesEZuQHt_K971wSESCUW7g5b6fArLWdmk3zcn7n-N5dD6iHpWkMvDaI2ORdmrHzYd22oN3gzcrscxYuJwXzy4OrzzwNg3CC/s1600-h/image23.png" style="display: block;"><img alt="image" border="0" height="72" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiT2qTv_eRlhyphenhyphenB3zUMZ5e1GnKzke8xxzGUfFif4iU9dMgDW5-X4l9bO0q4vCr2awLy6j31Fnszupt3WPXwP6oVx40CsoMlJdCmrVmK9_EfUa6hWBgKu05QjiPcU95sGrXWwiXoCXHVWJXKH/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="176" /></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw8wj80m8e-JsamMDYlcsNCIhbEbydpfQiKPVYOjILOjrb8Jf_jRPlvVyyAnx1sZSt2pyqu-ZBsvHk8-EXNw9Hbhj-hpIS3KxDwGgm8wb5X7fSuCmTOTw_I6PdrTOD2MuD_xvGfiSbVqiB/s1600-h/image22.png" style="display: block;"><img alt="image" border="0" height="121" src="http://lh3.ggpht.com/_fCDAga0oaOc/TX9FCo6hgBI/AAAAAAAABJk/hJfZ3bOJngA/image_thumb10.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="184" /></a> Still with me? I hope so. I know – it’s a bit long the first time, but it’s really pretty simple and will be worth the effort. Hang in there… Next, if you haven’t already done so, open up the Chinook Visual Studio Solution. We are now going to add the POCO generator to the EF Data Model. If you don’t have the ADO.NET POCO Entity Generator template installed, you will need to add it via the Visual Studio Extension Manager from the Visual Studio Gallery.
<h4>Adding the POCO Template</h4><ul><li>Open up the Chinook.edmx file so the EF data model is visible in the designer (this is located in the Chinook.Data.EF project) <br />
</li>
<li>Right-click on an empty area of the EF data model canvas and select ‘Add Code Generation Item…’</li>
</ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgLG1Y_yvW6D46xqj-tyLF5TOJwUFOaLd3uCHr-wwQ2-zFf1WLcb7BxrcLTUeEjIXOkDWaeCejOaawPu-2ChAM-Yn0nw7hgbtDmi0JWPISnlM2sZnMyE_uLTQybydTTcVIpUj-u5SmEZPb/s1600-h/p2addcodegen3.png" style="display: block;"><img alt="p2addcodegen" border="0" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTRzCOnK_FN4W0TM-zcovZXOkzVhyphenhyphend2oRsZEO_mCbyiDzsoxFU2s1IZe8deB7rCsV9BcFwkXFOlaa1DjPVmVBdA7IHueBO_sM75v8-MOrdqAGKQyeDzZnYPb08LA1hJgMOqhyoz0SDPS09/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="p2addcodegen" width="286" /></a>
<ul><li>This will bring up the ‘Add new Item Dialog,’ in which you will choose the ADO.NET POCO Entity Generator template (via the Installed Templates –> Code node)</li>
</ul><a href="http://lh6.ggpht.com/_fCDAga0oaOc/TX9FDpJgm7I/AAAAAAAABJw/j_V4PuDA1q8/s1600-h/p2addpoco3.png" style="display: block;"><img alt="p2addpoco" border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaz-xPourEFOKxERbwrbZroEtG0gX3gRkgsz_cflLPX_dT8c4hESrl5NKW14KQ8QOSleGuBu1eHFnO3Iby8nLIKFDMjpevwWsq97lAaZniX98jTO1QjPyeidXZRZ99Vs-mnauUmCKRyxbe/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="p2addpoco" width="534" /></a>
<ul><li>Set the ‘Name’ of the ADO.NET POCO Entity Generator item to ‘Poco.tt’ <br />
</li>
<li>Save the EF data model (edmx file) and build the Chinook.Data.EF project. <br />
</li>
<li>Delete the Poco.tt file from the Chinook.Data.EF project <br />
<ul><li>** DO NOT delete the Poco.Context.tt file.<span class="Apple-style-span" style="font-weight: bold;"> </span></li>
</ul></li>
</ul><h4>Add the T4 Templates to the Solution</h4>We are now going to add the T4 templates that we generated earlier.
<table border="0" cellpadding="2" cellspacing="0" style="width: 641px;"><tbody>
<tr> <td valign="top" width="175"><strong>Project</strong></td> <td valign="top" width="179"><strong>Directory</strong></td> <td valign="top" width="285"><strong>T4 Template (<strong>Solution directory</strong>)</strong></td></tr>
<tr> <td valign="top" width="175">Chinook.Core</td> <td valign="top" width="179">Domain</td> <td valign="top" width="285">Domain.Poco.tt</td></tr>
<tr> <td valign="top" width="175">Chinook.Core</td> <td valign="top" width="179">Domain</td> <td valign="top" width="285">Domain.Poco.Metadata.tt</td></tr>
<tr> <td valign="top" width="175">Chinook.Core</td> <td valign="top" width="179">Repository</td> <td valign="top" width="285">Repository.Interface.tt</td></tr>
<tr> <td valign="top" width="175">Chinook.Core</td> <td valign="top" width="179">Services</td> <td valign="top" width="285">Service.Interface.tt</td></tr>
<tr> <td valign="top" width="175">Chinook.Data.EF</td> <td valign="top" width="179">* add using Project node *</td> <td valign="top" width="285">Repository.Implementation.EF.tt</td></tr>
<tr> <td valign="top" width="175">Chinook.Infrastructure</td> <td valign="top" width="179">Services</td> <td valign="top" width="285">Service.Implementation.tt</td></tr>
<tr> <td valign="top" width="175"></td> <td valign="top" width="179"></td> <td valign="top" width="285"></td></tr>
</tbody></table>
For each one of the following directories in the list above, add the associated T4 template in listed order by right-clicking the respective directory, clicking ‘Add / Existing Item…’, navigating to the T4_EF4_Repository/<strong><u>Solution</u></strong> directory (in the root of the solution) and selecting the associated T4 template. A couple of notes…
<ul><li>You may need to use the ‘All File(*.*)’ filter on the ‘Add Existing Item’ dialog. <br />
</li>
<li>Ensure that you select the proper T4 templates (e.g. use the ‘<strong><u>Solution</u></strong>’ directory and NOT the ‘Source’ directory)</li>
</ul><a href="http://lh5.ggpht.com/_fCDAga0oaOc/TX9FEHNN3gI/AAAAAAAABJ4/kxxWcD2DxDI/s1600-h/image61.png" style="display: block;"><img alt="image" border="0" height="179" src="http://lh5.ggpht.com/_fCDAga0oaOc/TX9FEYtQIrI/AAAAAAAABJ8/vN1wJ-SOnB4/image_thumb2.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="511" /></a> <a href="http://lh6.ggpht.com/_fCDAga0oaOc/TX9FElEg4fI/AAAAAAAABKA/Z-RVN9iIW1g/s1600-h/image27.png" style="display: block;"><img alt="image" border="0" height="121" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGrLDOg_sEuY2IaVmINSVoEHxh39jKGva7sy8dv3OYOvwssnrIUQ6tWsrcRuETPBWhxiMY03yUTWlmffEOuvZR5g1e0iKKRJg0OoeQSBen2YhZWsnH_aT7ymeAAo3nrkiHytEEJd2klbZ1/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="184" /></a>
<h4>Build the Solution and Resolve Dependencies</h4>Now, go ahead and build the solution and resolve any dependencies that appear in the Error List. You will get errors on the ‘ObjectContext’ derived class (ChinookEntities in our scenario). To resolve these errors, you will need to add a reference to the Domain namespace where the POCOs classes live (we identified this earlier in the ‘namespace’ table). In our scenario, just add the following using statement to the ‘ChinookEntities’ class…
<div style="font-size: 11px;"><pre class="brush: csharp">using Chinook.Core.Domain;
</pre></div>Build the solution again. All the dependencies should now be resolved and the solution should build with no errors. In summary, we walked through the process of implementing a solution that separates concerns into specific behaviors using the <a href="http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx" target="_blank">Entity Framework</a> 4 and the <a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank">Repository</a> and <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank">Unit of Work</a> Patterns using T4 templates to generate the code using our EF data model<br />
<br />
In the next post in this series, we will review a few of the generated class/interfaces that the T4 code generation templates created.<br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com2tag:blogger.com,1999:blog-2933401848965498544.post-78188726358398072472011-03-10T15:01:00.022-05:002011-03-15T07:52:47.131-04:00Another Entity Framework 4 Repository & Unit of Work Solution–Intro and Part 1: SetupEntity Framework Code First (EF Code First) has been getting quite a bit of press lately. I’ve done some ‘play’ development using EF Code First; however, the powers that be seem to keep bringing me back to the Model First (create database/ERD and then the application code) paradigm.<br />
<br />
What I really like about EF Code First is the seamless use of Separation of Concerns. My next few posts are going to be a series of entries on using the Model First approach to take advantage of Separation of Concerns.<br />
<br />
Rather than discuss software development and design theory, these posts will walk through the process of implementing a solution that separates concerns into specific behaviors using the <a href="http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx" target="_blank">Entity Framework</a> 4 and the <a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank">Repository</a> and <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank">Unit of Work</a> Patterns. To facilitate this process, we will be using T4 templates.<br />
<br />
While there are many solutions online that create similar implementations, this series will focus on a process that I really like, fits my needs, and is easy to understand. That last point is important – ‘easy to understand.’ Separation of Concerns and all the concepts that come along with it can be very overwhelming if you’re coming from ASP.NET Web Forms…<br />
<br />
Forewarning – this series of posts contain quite a few steps. I considered creating a <a href="http://nuget.org/" target="_blank">NuGet</a> package; however, I couldn’t settle on the structure of the package and I realized that I started losing focus on the intent of my madness. I also considered creating a few Visual Studio templates; however, my experience with VS templates is limited, and once again the madness had me losing focus. That said, hopefully this series and the steps involved will not be too overwhelming. I feel the value of the final results far exceed the steps involved in getting there… <br />
<br />
UPDATE: the NuGet team is considering adding functionality where <a href="http://nuget.codeplex.com/workitem/818?ProjectName=nuget" target="_blank">NuGet could be run from PowerShell outside of Visual Studio</a>. This means that one could create a NuGet package that would create a solution with x number of projects and add dependencies to those projects, files, etc… If that functionality was available now, I could deploy all the steps involved here in a single NuGet package – eliminating MOST of the steps on this series. If this sounds cool – it is cool – vote for this functionality <a href="http://nuget.codeplex.com/workitem/818?ProjectName=nuget" target="_blank">here</a>.<br />
<br />
Okay, so here is the series breakdown:<br />
<ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository.html">Part 1: Setup</a><br />
<ul><li>This post involves downloading and creating the SQL Server database, setting up the Visual Studio solution and project structure, and generating the out-of-the-box Entity Framework (EF/EF4) data model from the newly created database.</li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_15.html">Part 2: Creating the Repositories and Unit of Work (UoW)</a><br />
<ul><li>This is the meat of the series. This post includes downloading some T4 templates, settings a few parameters, and generating the Repositories and Unit of Work (UoW) using the T4 templates and EF4 data model.</li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_5988.html">Part 3: Review Some of The Generated Code</a><br />
<ul><li>This post will review a few of the generated class/interfaces that the T4 code generation created. </li></ul><li><a href="http://tdryan.blogspot.com/2011/03/another-entity-framework-4-repository_816.html">Part 4: Using EF, Repository & UoW in an ASP.NET MVC 3 Project</a><br />
<ul><li>This post includes wiring up the EF4 data model, repositories, and UoW to <a href="http://structuremap.net/structuremap/" target="_blank">StructureMap</a> dependency injection container and use of these products in an ASP.NET MVC 3 Web application project.</li></ul></li></ul>Lets get started…
<h3>Part 1: Setup</h3>As stated above, in Part 1 we are going to create a database, create a Visual Studio solution and project structure, and generate an EF4 data model that points to our database.
<h4>1) Create a database</h4>For this series, we are going to use the <a href="http://chinookdatabase.codeplex.com/releases/view/55169" target="_blank">Chinook</a> database. Specifically, we are going to use the <a href="http://chinookdatabase.codeplex.com/releases/view/55169" target="_blank">Chinook</a> version 1.2 for SQL Server. You can download the <a href="http://chinookdatabase.codeplex.com/releases/view/55169" target="_blank">Chinook database from CodePlex</a> – make sure you download version 1.2 – in preparing for this series, I had issues generating EF4 Navigation Properties with Chinook version 1.3, so please use version 1.2. The download contains two SQL scripts for generating the Chinook database. Please use the SQL Script that generates table primary keys with <a href="http://msdn.microsoft.com/en-us/library/ms186775.aspx" target="_blank">IDENTITY</a>. Once the Chinook database is generated, the database should similar to the following screenshot from SQL Server Management Studio (SSMS): <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzwi9ROzqADROeDPSL5EoplH9E7yyTgVqJekzl5kd7RoDbFA5a8wGtnRi7f1UDUt0ve_TqBlS0Qr6t3q7_mCan66jELv3makp2-E58gnsbkO9QoH1loAidHNqSgBsSNOdoJMB4B9QsZi-P/s1600-h/ChinookSsms3.png" style="display: block;"><img alt="ChinookSsms" border="0" height="306" src="http://lh6.ggpht.com/_fCDAga0oaOc/TX9BL9fT4CI/AAAAAAAABHs/kgPnCgNEAyg/ChinookSsms_thumb1.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="ChinookSsms" width="185" /></a>
<h4>2) Visual Studio Solution and Project Structure</h4>The solution and related projects architecture that we are going to use loosely follows the <a href="http://jeffreypalermo.com/blog/the-onion-architecture-part-1/" target="_blank">Onion Architecture Pattern</a> – this is a great read and well worth the time…
<ol><li>Create an empty Visual Studio Solution. <ul><li>Open Visual Studio<br />
</li>
<li>Click ‘File’ –> ‘New’ –> ‘Project’<br />
</li>
<li>Under the ‘Installed Templates,’ select the ‘Other Project Types’ node in the project tree, select the ‘Visual Studio Solutions’ node, and then select the ‘Blank Solution.’ Name the solution ‘Chinook.’ Here’s a screenshot of the New Project Wizard:<br />
<a href="http://lh3.ggpht.com/_fCDAga0oaOc/TX9BMFf3HuI/AAAAAAAABHw/n_eMXuSBmv8/s1600-h/solutionwizard4.png" style="display: block;"><img alt="solutionwizard" border="0" height="379" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9yGTP3AQ1H44QGGH-RL77oM0up_S4oZ04HDfq_BYqXmv1jfvkQRjduwuKW7ZGSmAVJNOrqT7G0oHkhwHJykPCQ27wQaqxaUo0vfXC5BRBH_6lOWy-4AwsRehe_FMfY1-P1A-qXeozXA9V/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="solutionwizard" width="465" /></a> </li>
</ul></li>
<li>Create the following three Class Library Projects. Delete the auto-generated ‘Class1.cs’ file that was added to each project. <ul><li>Chinook.Core <ul><li>See details in the next step</li>
</ul></li>
<li>Chinook.Data.EF <ul><li>This is where the Repository Implementations and Unit of Work classes will live.</li>
</ul></li>
<li>Chinook.Infrastructure <ul><li>This is where the Service Implementations will live.</li>
</ul></li>
</ul></li>
<li>Create the following three directories within the <strong>Chinook.Core Project</strong>: <ul><li>Domain <ul><li>This is where the Domain Model object will live.</li>
</ul></li>
<li>Repository <ul><li>This is where the Repository Contracts will live.</li>
</ul></li>
<li>Services <ul><li>This is where the Service Contracts will live</li>
</ul></li>
</ul></li>
<li>Create the following directory within the <strong>Chinook.Infrastructure Project</strong>: <ul><li>Services</li>
</ul></li>
</ol>At this point, the Chinook Solution should look similar to the following screenshot: <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyXMrZaLNf3NWZjt5gwepDzGm7Nc5ieNpvLY3yKp1HkKkV-suzLpOTc6a0RPVKiEHcCC2LsdW9Ppg8z6lRkACdDMsAjmrf-74q7xkF5GHluUcNDilEOIoWZfKEbdb4d0KHtSUmqbmpcLyo/s1600-h/solutionShot002.png" style="display: block;"><img alt="solutionShot00" border="0" height="244" src="http://lh3.ggpht.com/_fCDAga0oaOc/TX9BM_tcORI/AAAAAAAABH8/OjwITvZe83I/solutionShot00_thumb.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="solutionShot00" width="192" /></a>
<h4>3) Generate an EF4 Data Model from an Existing Database</h4>Right-click the <strong>Chinook.Data.EF Project</strong> and select ‘Add / New Item…’ <a href="http://lh6.ggpht.com/_fCDAga0oaOc/TX9BNAmOQnI/AAAAAAAABIA/TydRX_YdjU4/s1600-h/efmWizard003.png" style="display: block;"><img alt="efmWizard00" border="0" height="409" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0DydalqmeXJWXK4sGV9j8HdxwoWgXJtZ_PrfSg7CytaK09970MHa6SzIBkv2P_f9gchf9P_4Qtmkg5TzYzYXWtFLx0i7ZHJAZ9TjxStd9cuknelJfbuhDxeJGQWIfmQkYTSD2OH8HAW8z/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="efmWizard00" width="535" /></a> Next, select ADO.NET Entity Data Model from the Data Templates list, name it ‘Chinook,’ and click ‘Add’ <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvu2JlyZYv9UkJnfa4xVMSIK4E2rt2eFA_Jym0RikzAan4bBKjKNqxdsxrm5w0D-1XKJbqWbND-bVDsYB36jyZS6Wjcpl7G9WJxRFKLoAxC6FR0opb_WeXSsTba9Ruufc_ASzBGs_8cFah/s1600-h/efmWizard014.png" style="display: block;"><img alt="efmWizard01" border="0" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkP8L_Y8w3O6Y3IWkpkH_3oz3uoVj-tkaYdi7KfYvMbzXqunPxcZFl7ho_Zh92FiOFcaf_goV-3Xh2Hg7j5KV5e-6jw2uA8CbgiYvhXBtJOSjS_1IXOwsY8OS6gvWtSRsqhTzCVf0jk7H4/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="efmWizard01" width="550" /></a> Next, select ‘Generate from database’ and click ‘Next’ <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQGS9bgmlXaMa4LV8rXHkMNuDGcTavpu2LXKfHNp67FCYbsh1882VUz12qunW90l2WT6RQHHBGjQhCaIjQqOw-CSE8L2H-hAkO7zW-allMlkJHMdjDn5Tcmu5s2hcIVscv64iPHGD0vw6m/s1600-h/efmWizard023.png" style="display: block;"><img alt="efmWizard02" border="0" height="375" src="http://lh5.ggpht.com/_fCDAga0oaOc/TX9BOFuR0aI/AAAAAAAABIU/dea_xgFMCuA/efmWizard02_thumb1.png?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="efmWizard02" width="424" /></a> Now it’s time to point the EF Data Model to the Chinook database created in step ‘1) Create a Database.’ Go ahead and locate your database (or create a New Connection) and make sure that it is selected in the database drop-down-list. Also, click the ‘Save entity connection settings in App.Config as:’ checkbox and leave the default Connection settings name. Next click ‘Next.’ <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIh3WS7-4DSNvVTqJnKnQNxb4Rxe1E1GwtQK3EsugVM0QinCxSWz8ISreJkFDkS-d-Y1aIwOnVfmUr1mu_fie4A9QRDb8t1eAvllzK1axRDpBqXOMUEwGf_6NkI48Vnm610E_G6BHMNElh/s1600-h/efmWizard033.png" style="display: block;"><img alt="efmWizard03" border="0" height="422" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioxTSCu10jklrn4M3hhAddoogxybrNPNFYU_gGCK1nB33jYpIQyJ41qi_YGD6XXylRoii-rau2e4q7S6abtuOD9dJ1FqLaw9u0m8SOHXL7bRyCXuyGR4nwjgo64hujJ-Moq9m6SSmJHqtq/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="efmWizard03" width="468" /></a> Next, choose the database object that you want to model. For this series, just choose the ‘Table’ objects by selecting the checkbox next to the ‘Tables’ node. Click both of the checkbox options and the default Model Namespace and click ‘Finish.’ <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFcpxQv-JK0WY5VJ3Z0yO2xOofNHdgyemhh5wg2vOF5bBE11R1chDOS3r8urlYds1vslfvCFrgshlOEvpGr1JG7vBS8Q0HfG5wdFTi1MOR1RvBCMJkmgRfxPkizIu0rgqzLZhQTUIj6hvU/s1600-h/efmWizard044.png" style="display: block;"><img alt="efmWizard04" border="0" height="416" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEQDI8UGMrCSx-eb1-MVTV7nD4vf8Hno2gPtVRzKW9CvgwUVgkmlyIVhazfaByHmIpqvtDdCYkQFOXtyHl4s52JQQhSk9OWb_YXHkcj75EgNgzZ5ZyMVf8icgqQxYjV9lvfYhyz4c02cld/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="efmWizard04" width="457" /></a> The result is the EF data model that points to the 'Chinook’ database – Chinook.edmx <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB3veG_uCj1JylURKp-gklbytt8vRy_zyMvXJWmUgxhcju1zpf_DlEm5-_BfGWVNcG02n9KlDCo9-rizG6CipDQSqZIQC0ZVUvfz0-CUKTW-1o2dFYTB-qjecuChBYXlPcv4lXFosKjbkJ/s1600-h/efmWizard057.png" style="display: block;"><img alt="efmWizard05" border="0" height="687" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAH9mq_l2xYz9Fnu1tC_PHxh3AvcaajE0tmD5J1cTiKOf-rHpzkQMat8N2ZU3_KtMqIjWDG8qcWipvsbK4d_YR8L4XCeY4DIxSbH_9lD1jZtYp9RuODoJS-WMSa9ydofBCXGQC4aUr1uon/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="efmWizard05" width="1013" /></a> Save the file and build the Chinook Solution. A few more steps before we wrap Part 1 up…
<ol><li>Add a reference to the ‘System.ComponentModel.DataAnnotations’ assembly to the Chinook.Core project.<br />
</li>
<li>Add a reference to the Chinook.Core project to the other two projects: Chinook.Data.EF and Chinook.Infrastructure<br />
</li>
<li>Make note of the namespaces of the following three directories within the Chinook.Core project – you will need these for Part 2 of the series</li>
</ol><table border="0" cellpadding="2" cellspacing="0" style="width: 400px;"><tbody>
<tr> <td valign="top" width="133"><strong><u>Directory</u></strong></td> <td valign="top" width="267"><strong><u>Namespace</u></strong></td></tr>
<tr> <td valign="top" width="133">Domain</td> <td valign="top" width="267">Chinook.Core.Domain</td></tr>
<tr> <td valign="top" width="133">Repository</td> <td valign="top" width="267">Chinook.Core.Repository</td></tr>
<tr> <td valign="top" width="133">Services</td> <td valign="top" width="267">Chinook.Core.Services</td></tr>
</tbody></table>In summary, we’ve created a new database, created a new Visual Studio application solution and project structure, and generated an Entity Framework data model from an existing database.<br />
<br />
In the next post in this series, we’ll walk though the steps of creating Plain Old CLR Objects (POCOs) Repositories, Services, and a Unit of Work (UoW) using some T4 templates to generate all the aforementioned code.<br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com6tag:blogger.com,1999:blog-2933401848965498544.post-29159638876691538032011-02-22T09:29:00.001-05:002011-03-22T09:41:27.736-04:00How I NuGet - Creating a NuGet Package–Without a batch fileThis is a follow-up to a previous post <a href="http://tdryan.blogspot.com/2011/02/how-i-nuget-creating-nuget-package.html" target="_blank">How I NuGet – Creating a NuGet Package</a> where I used a batch file to create my NuGet package.<br />
<br />
The batch file is not a necessary step in the process – it’s just a preference of mine. However, after refactoring the process to use the NuGet native commands to include files, I’m leaning toward eliminating the batch step in my process. Recall the following high-level outline of the steps used to create the NuGet package from the previous post:<br />
<ol><li>Download the NuGet Command Line tool<br />
</li>
<li>Create a generic nuget nuspec file - the nuget manifest file<br />
</li>
<li>Update the nuget manifest with project specific settings<br />
</li>
<li><strike>Create a batch file (.bat) file that will serve as the main entry point into the nuget package creation process </strike><br />
</li>
<li>Create the nuget package<br />
</li>
<li>Submit and contribute the package to the NuGet Gallery</li>
</ol>Eliminating step 4, creation of the batch file and updating step 3, Update the NuGet manifest settings to the following:<br />
<br />
<div style="font-size: 11px"><pre class="brush: xml"><?xml version="1.0"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>MvcContrib.Shp</id>
<version>1.0.0.0</version>
<authors>Dan Ryan</authors>
<owners>Dan Ryan</owners>
<licenseUrl>http://mvcxgridmenu.codeplex.com/license</licenseUrl>
<projectUrl>http://mvcxgridmenu.codeplex.com/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>UI Extensions to the MvcContrib Project - Themed Grid & Menu</description>
<tags>MVC MVC3 ASP.NET MvcContrib</tags>
<dependencies>
<dependency id="MicrosoftWebMvc" version="2.0" />
<dependency id="MvcContrib.Mvc3-ci" version="3.0.57.0" />
</dependencies>
</metadata>
<files>
<file src="..\src\MvcContrib.Shp\MvcContrib.Shp\bin\Release\MvcContrib.Shp.dll" target="lib" />
<file src="..\src\MvcContrib.Shp\Shp.Web\Scripts\jquery.mvccontrib*.*" target="content\Scripts" />
<file src="..\src\MvcContrib.Shp\Shp.Web\Scripts\superfish.js" target="content\Scripts" />
<file src="..\src\MvcContrib.Shp\Shp.Web\Scripts\*jquery.hoverIntent*" target="content\Scripts" />
</files>
</package>
</pre></div><br />
The XML files element in the snippet above will include the child file elements in the NuGet package and place the respective file in the associated target (destination directory) of the NuGet package – the snippet above uses targets of lib and content. You can read all above the files element and other NuGet file specifications here: <a href="http://nuget.codeplex.com/documentation?title=Nuspec%20Format" target="_blank">.nuspec File Format</a><br />
<br />
Again, this is an alternative (and recommended) way to create a NuGet package. All the other steps in the high-level outline of steps (above) remains the same.<br />
<br />
Thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-84026905035402269082011-02-21T15:11:00.025-05:002011-02-22T09:32:28.675-05:00How I NuGet - Creating a NuGet Package<style type="text/css">
div.cs-47dfa1c4-jack-4f72-a158-6dd20fdde95f {white-space: pre; line-height: 1; background: #fff; padding: 5px; margin: 5px;}
span.sc5-47dfa1c4-jack-4f72-a158-6dd20fdde95f, span.sc0-47dfa1c4-jack-4f72-a158-6dd20fdde95f { font-family: 'Courier New'; font-size: 10pt; color: #000;}
span.sc5-47dfa1c4-jack-4f72-a158-6dd20fdde95f {color: #0080ff}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a {white-space: pre; line-height: 1; background: #fff; padding: 5px; margin: 5px;}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a span {font-family: 'Courier New';font-size: 10pt; color: #000000;}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a .sc0 {}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a .sc1 {color: #008000;}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a .sc2 {font-weight: bold;color: #0000ff;}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a .sc6 {font-weight: bold;color: #ff8000; background: #fcfff0;}
div#sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a .sc7 {font-weight: bold;color: #ff0000;}
</style><br />
Update: <a href="http://tdryan.blogspot.com/2011/02/how-i-nuget-creating-nuget.html">How I NuGet - Creating a NuGet Package – Without a batch file</a><br />
<br />
I started toying around with the MvcContrib project a couple of months ago. Since then, I created a few UI extensions that use the MvcContrib project. I wanted to contribute to the project; however, Jeremy Skinner recommended that I create a NuGet package and distribute my contributions that way. So, that's what I did and this post describes/outlines the steps I used to create the NuGet package.<br />
<br />
The source for the MvcContrib UI extensions suggested above is available on CodePlex here: <a href="http://mvcxgridmenu.codeplex.com/" target="_blank">MvcContrib UI Extensions - Themed Grid & Menu</a><br />
<br />
My assumption is that you are familiar with NuGet. If not, you can read all about it at its <a href="http://mvccontrib.codeplex.com/" target="_blank" title="MvcContrib Project">CodePlex project site</a>.<br />
<br />
Here is a high level outline of the steps that I used to create my NuGet package:<br />
<ol><li>Download the NuGet Command Line tool <br />
</li>
<li>Create a generic nuget nuspec file - the nuget manifest file <br />
</li>
<li>Update the nuget manifest with project specific settings <br />
</li>
<li>Create a batch file (.bat) file that will serve as the main entry point into the nuget package creation process <br />
</li>
<li>Create the nuget package <br />
</li>
<li>Submit and contribute the package to the NuGet Gallery </li>
</ol>For reference, the following is a snippet of my directory structure used in the MvcContrib UI Extensions. I will reference this structure in the steps below. This image will also help with understanding the batch file used in the steps below.<br />
<br />
<div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuf99hijUxrX1cYLuv-jGMXbuUjDVNZ0ojbjOnFfdelKwZvns13o4c4jAx8QFvHd3aSd3tEb5s0hNwUu1MFxYVunP9mU8maVoCZf5GSDB2zpO24TXE9q490PTlz0wI7nbO3AvgnMXVRqMh/s1600/mvcuixs.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuf99hijUxrX1cYLuv-jGMXbuUjDVNZ0ojbjOnFfdelKwZvns13o4c4jAx8QFvHd3aSd3tEb5s0hNwUu1MFxYVunP9mU8maVoCZf5GSDB2zpO24TXE9q490PTlz0wI7nbO3AvgnMXVRqMh/s320/mvcuixs.png" width="137" /></a></div><h4> </h4><h4>1. Dowload the NuGet Command Line tool</h4>Easy - download the NuGet command line tool <a href="http://nuget.codeplex.com/releases" target="_blank">here</a>. Using our structure above, put the .exe into the MvcContrib.Shp/nuspec/ directory.<br />
<br />
<h4>2. Create a generic nuget nuspec file - the nuget manifest file</h4>Create the .nuspec file by running the following command from the dos prompt:<br />
<br />
<div class="cs-47dfa1c4-jack-4f72-a158-6dd20fdde95f"><span class="sc5-47dfa1c4-jack-4f72-a158-6dd20fdde95f">nuget</span><span class="sc0-47dfa1c4-jack-4f72-a158-6dd20fdde95f"> spec</span></div>This will create a file by with the name of Package.nuspec. All this is is an xml file that describes the details of the package - formally called a package manifest or specification. While renaming this file is not required, I think it makes sense to give it the same name as that of the resulting NuGet package - in our scenario, MvcContrib.Shp.nuspec.<br />
<br />
<h4>3. Update the nuget manifest with project specific settings</h4>The NuGet <a href="http://nuget.codeplex.com/documentation?title=Nuspec%20Format" target="_blank">.nuspec file format specification</a> contains many configuration details; however, for our scenario I’ve updated the .nuspec file to contain the following content:<br />
<br />
<div style="font-size: 11px;"><pre class="brush: xml"><?xml version="1.0"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<id>MvcContrib.Shp</id>
<version>1.0.0.0</version>
<authors>Dan Ryan</authors>
<owners>Dan Ryan</owners>
<licenseUrl>http://mvcxgridmenu.codeplex.com/license</licenseUrl>
<projectUrl>http://mvcxgridmenu.codeplex.com/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>UI Extensions to the MvcContrib Project - Themed Grid & Menu</description>
<tags>MVC MVC3 ASP.NET MvcContrib</tags>
<dependencies>
<dependency id="MicrosoftWebMvc" version="2.0" />
<dependency id="MvcContrib.Mvc3-ci" version="3.0.57.0" />
</dependencies>
</metadata>
</package>
</pre></div>The XML elements are pretty self-explanatory; however, I recommend reading the NuGet <a href="http://nuget.codeplex.com/documentation?title=Nuspec%20Format" target="_blank">.nuspec file format specification</a> for details on each element.<br />
<br />
<h4>4. Create a batch file (.bat) that will serve as the main entry point into the nuget package creation process</h4>This step is not necessary; however, I like batch files. Batch files give us the ability to place simple, repeatable logic into a batch file and execute that logic by double-clicking the batch file. The following batch file creates a temp directory with subdirectories for the NuGet package content, copies the files (.dll, and .js files) from the source directories and places these files in the temp content directories, executes the NuGet.exe pack command, and then cleans up by removing the temp directories. Again, this could have all been done via the .nuspec file, but I just prefer to use the batch. Here’s the batch file contents: <br />
<br />
<pre><div id="sc-63dfa1c4-bayl-4f35-a158-6dd20fdde62a"><span class="sc2">echo</span><span class="sc0"> OFF
</span><span class="sc1">:: root nuspec directory
</span><span class="sc2">set</span><span class="sc0"> rootDirectory</span><span class="sc7">=</span><span class="sc6">%cd%</span><span class="sc0">
</span><span class="sc1">:::::::::::::::::::::::::::::::::
:: 1) build the destination directory structure
:::::::::::::::::::::::::::::::::
</span><span class="sc0">
</span><span class="sc1">:: destination structure
</span><span class="sc2">set</span><span class="sc0"> baseDirectory</span><span class="sc7">=</span><span class="sc0">basenuspec
</span><span class="sc2">set</span><span class="sc0"> contentDirectory</span><span class="sc7">=</span><span class="sc0">content
</span><span class="sc2">set</span><span class="sc0"> libDirectory</span><span class="sc7">=</span><span class="sc0">lib
</span><span class="sc2">set</span><span class="sc0"> scriptsDirectory</span><span class="sc7">=</span><span class="sc0">Scripts
</span><span class="sc1">:: make directory command
</span><span class="sc2">set</span><span class="sc0"> makeDirectoryCommand</span><span class="sc7">=</span><span class="sc0">MKDIR
</span><span class="sc1">:: delete directory command
::set deleteDirectoryCommand=DEL /f
</span><span class="sc2">set</span><span class="sc0"> deleteDirectoryCommand</span><span class="sc7">=</span><span class="sc0">RMDIR /s /q
</span><span class="sc1">:: delete the previous package build files and directories - if they were not deleted before
</span><span class="sc6">%deleteDirectoryCommand%</span><span class="sc0"> </span><span class="sc6">%baseDirectory%</span><span class="sc0">
</span><span class="sc1">:: build the directory structure
</span><span class="sc6">%makeDirectoryCommand%</span><span class="sc0"> </span><span class="sc6">%baseDirectory%</span><span class="sc0">
</span><span class="sc2">cd</span><span class="sc0"> </span><span class="sc6">%baseDirectory%</span><span class="sc0">
</span><span class="sc6">%makeDirectoryCommand%</span><span class="sc0"> </span><span class="sc6">%libDirectory%</span><span class="sc0">
</span><span class="sc6">%makeDirectoryCommand%</span><span class="sc0"> </span><span class="sc6">%contentDirectory%</span><span class="sc0">
</span><span class="sc2">cd</span><span class="sc0"> </span><span class="sc6">%contentDirectory%</span><span class="sc0">
</span><span class="sc6">%makeDirectoryCommand%</span><span class="sc0"> </span><span class="sc6">%scriptsDirectory%</span><span class="sc0">
</span><span class="sc1">:: navigate to the root directory
</span><span class="sc2">cd</span><span class="sc0"> </span><span class="sc6">%rootDirectory%</span><span class="sc0">
</span><span class="sc1">:::::::::::::::::::::::::::::::::
:: 2) copy files from source to destination
:::::::::::::::::::::::::::::::::
</span><span class="sc0">
</span><span class="sc1">:: relative path to the MvcContrib.Shp.dll
</span><span class="sc2">set</span><span class="sc0"> srcLibDirectory</span><span class="sc7">=</span><span class="sc0">..\src\MvcContrib.Shp\MvcContrib.Shp\bin\Release\
</span><span class="sc1">:: relative path to source script files
</span><span class="sc2">set</span><span class="sc0"> srcScriptsDirectory</span><span class="sc7">=</span><span class="sc0">..\src\MvcContrib.Shp\Shp.Web\Scripts\
</span><span class="sc1">:: lib files to copy
</span><span class="sc2">set</span><span class="sc0"> libFiles</span><span class="sc7">=</span><span class="sc0">MvcContrib.Shp.dll
</span><span class="sc1">:: script files to copy
</span><span class="sc2">set</span><span class="sc0"> scriptFiles</span><span class="sc7">=</span><span class="sc0">jquery.mvccontrib</span><span class="sc7">*</span><span class="sc0">.</span><span class="sc7">*</span><span class="sc0"> superfish.js </span><span class="sc7">*</span><span class="sc0">jquery.hoverIntent</span><span class="sc7">*</span><span class="sc0">
</span><span class="sc1">:: copy commnad
</span><span class="sc2">set</span><span class="sc0"> copyCommand</span><span class="sc7">=</span><span class="sc0">COPY /y
</span><span class="sc1">:: copy the source dll to the lib destination directory
</span><span class="sc6">%copyCommand%</span><span class="sc0"> </span><span class="sc6">%srcLibDirectory%</span><span class="sc0">\</span><span class="sc6">%libFiles%</span><span class="sc0"> </span><span class="sc6">%rootDirectory%</span><span class="sc0">\</span><span class="sc6">%baseDirectory%</span><span class="sc0">\</span><span class="sc6">%libDirectory%</span><span class="sc0">\
</span><span class="sc1">:: navigate to the root directory
</span><span class="sc2">cd</span><span class="sc0"> </span><span class="sc6">%rootDirectory%</span><span class="sc0">
</span><span class="sc1">:: navigate to the source scripts directory
</span><span class="sc2">cd</span><span class="sc0"> </span><span class="sc6">%srcScriptsDirectory%</span><span class="sc0">
</span><span class="sc1">:: copy the source scripts to the scripts destination directory
</span><span class="sc2">for</span><span class="sc0"> </span><span class="sc6">%%F</span><span class="sc2"> in</span><span class="sc0"> (</span><span class="sc6">%scriptFiles%</span><span class="sc0">)</span><span class="sc2"> do</span><span class="sc0"> </span><span class="sc6">%copyCommand%</span><span class="sc0"> </span><span class="sc6">%%F</span><span class="sc0"> </span><span class="sc6">%rootDirectory%</span><span class="sc0">\</span><span class="sc6">%baseDirectory%</span><span class="sc0">\</span><span class="sc6">%contentDirectory%</span><span class="sc0">\</span><span class="sc6">%scriptsDirectory%</span><span class="sc0">\
</span><span class="sc1">:: navigate to the root directory
</span><span class="sc2">cd</span><span class="sc0"> </span><span class="sc6">%rootDirectory%</span><span class="sc0">
</span><span class="sc1">:::::::::::::::::::::::::::::::::
:: 3) create the nuget package
:::::::::::::::::::::::::::::::::
</span><span class="sc0">
</span><span class="sc1">:: nuget pack command
</span><span class="sc2">set</span><span class="sc0"> packCommand</span><span class="sc7">=</span><span class="sc0">NuGet.exe pack
</span><span class="sc1">:: nuspec manifest file
</span><span class="sc2">set</span><span class="sc0"> manifest</span><span class="sc7">=</span><span class="sc0">MvcContrib.Shp.nuspec
</span><span class="sc1">:: run the nuget package command
</span><span class="sc6">%packCommand%</span><span class="sc0"> </span><span class="sc6">%manifest%</span><span class="sc0"> -b </span><span class="sc6">%baseDirectory%</span><span class="sc0">
</span><span class="sc1">:: delete the temp package build files and directories
</span><span class="sc6">%deleteDirectoryCommand%</span><span class="sc0"> </span><span class="sc6">%baseDirectory%</span><span class="sc0">
</span><span class="sc1">::PAUSE</span></div></pre>The above batch file is pretty much fully documented, so it shouldn’t take too much to understand the logic.<br />
<br />
Could I have used PowerShell to do this? Absolutely; however, I really haven't spent much time diving into PowerShell. Until then, the batch solution works just fine.<br />
<br />
As a side note - NuGet gives you the ability to add Content to the package (this is essentially what the previous batch file is doing); add pre-processing of files to the client project (the project importing the NuGet package); add XML elements to be merged with the client project's .config files; add PowerShell scripts to do anything else that the NuGet package requires; and a whole laundry list of other functionality. Again, if you're interested, check out the <a href="http://nuget.codeplex.com/" target="_blank">NuGet Project and Documentation on CodePlex</a>.<br />
<br />
<h4>5. Create the nuget package</h4>In our scenario, creating the NuGet package is simple. All you have to do is double-click the .bat file and the batch file handles the command to create the NuGet package. The resulting package is compiled into a single file. In our scenario and using the .nuspec file from above, the resulting package is compiled into: <strong style="color: #ff9900; font-size: 14px;">MvcContrib.Shp.1.0.0.0.nupkg</strong>. How is the package name composed? The following image identifies the package name components:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM3HYp7MGhwhd_8Qqdg18LnZ3H7SEapYPIWRXzE9RuJxw2P0EbgnBAW1o_LTq1RZXzZ9rIpUi-S60GP5WkuTiuB2HrjXikclCfmhJ25sRG2BTfCrqySarIY95alXnZRDiZJL2LegnG-zKv/s1600-h/nupkgname%5B2%5D.png"><img alt="nupkgname" border="0" height="54" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiznyx0MsPlP5pim0zZesG9i7UY1X2vIcJRtcyEUA6IRZflIWOTmaS-QPYQobLtmDP38MZKvC48gDwv9ZzWJDQ-rinA7FHTApA7jo2hiQBrgS1Q8Z_le1AZrckwg6CiMNHErTFzzkMdyYmO/?imgmax=800" style="background-image: none; border-bottom-width: 0px; border-left-width: 0px; border-right-width: 0px; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="nupkgname" width="244" /></a> <br />
<h4> </h4><h4>6. Submit and contribute the package to the NuGet Gallery</h4>Log into the <a href="http://nuget.org/" target="_blank">NuGet Gallery</a> and contribute your package. What? If you don’t already have an account, request one from the NuGet Gallery. The process of submitting/contributing you package for distribution is as simple as uploading and following the NuGet package wizard.<br />
<br />
Useful Links: <br />
<ul><li><a href="http://nuget.org/" target="_blank">NuGet Gallery</a> <br />
</li>
<li><a href="http://nuget.codeplex.com/" target="_blank">NuGet Project site</a> on CodePlex <br />
</li>
<li>Scott Hanselman’s post - <a href="http://www.hanselman.com/blog/CreatingANuGetPackageIn7EasyStepsPlusUsingNuGetToIntegrateASPNETMVC3IntoExistingWebFormsApplications.aspx" target="_blank">Creating a NuGet Package in 7 easy steps - Plus using NuGet to integrate ASP.NET MVC 3 into existing Web Forms applications</a> <br />
</li>
<li><a href="http://haacked.com/tags/NuGet/default.aspx" target="_blank">Phil Haack’s NuGet posts</a></li>
</ul>Anyway, thanks for reading…tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com1tag:blogger.com,1999:blog-2933401848965498544.post-89554602021091602732011-02-07T08:27:00.004-05:002011-02-16T17:45:44.390-05:00MvcContrib Menu<a href="http://tdanryan.com/mvccontrib/" target="_blank">Demo</a> | <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">Source</a><br />
<br />
This page is a placeholder for now; however, I intent to create a post that describes the use of my own version of the MvcContrib Menu Helper.<br />
<br />
For now, you can see a working demo by using the demo link. Once I have the source code cleaned up a bit, I'll post the source code.<br />
<br />
Below is a quick snippet of the code used to generate the main menu in the demo. Notice the fluent style and the use of Razor Templates. BTW, sorry for the poor color-code - Razor doesn't format well using <a href="http://alexgorbatchev.com/SyntaxHighlighter/" target="_blank">SyntaxHighligher</a>.<br />
<br />
<div style="font-size: 11px;"><pre class="brush: csharp">@Html.MvcContrib().Menu().Items(menu => {
menu.Action<HomeController>(c => c.Index(), "no text displayed", Url.Content("~/Content/ico/house.png"))
.ItemAttributes(@class => "solo").DisplayText(false);
menu.Link("About", null, Url.Content("~/Content/ico/application_side_boxes.png")).Items(sub => {
sub.Content(
@:@Html.Partial("_MvcContribLogo")
);
}).ListAttributes(style => "width: 450px;", @class => "sf-shadow-off");
menu.Link("Secure", null, Url.Content("~/Content/ico/lock_open.png")).Items(sub => {
sub.Secure<HomeController>(c => c.Index(), null, Url.Content("~/Content/ico/application_view_tile.png"));
sub.Secure<HomeController>(c => c.About(), null, Url.Content("~/Content/ico/info2.png"));
sub.Secure<HomeController>(c => c.SecurePageOne(), null, Url.Content("~/Content/ico/shield.png"));
sub.Secure<HomeController>(c => c.SecurePageTwo(), null, Url.Content("~/Content/ico/shield_go.png"));
});
menu.Link("Insecure", null, Url.Content("~/Content/ico/lock.png")).Items(sub => {
sub.Action<HomeController>(c => c.Index(), null, Url.Content("~/Content/ico/application_view_tile.png"));
sub.Action<HomeController>(c => c.About(), null, Url.Content("~/Content/ico/info2.png"));
sub.Action<HomeController>(c => c.SecurePageOne(), null, Url.Content("~/Content/ico/shield.png"));
sub.Action<HomeController>(c => c.SecurePageTwo(), null, Url.Content("~/Content/ico/shield_go.png"));
});
menu.Action<MenuController>(c => c.Index(), "Menu Examples", Url.Content("~/Content/ico/house_go.png"));
})
</pre></div><br />
<a href="http://tdanryan.com/mvccontrib/" target="_blank">Demo</a> | <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">Source</a>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com12tag:blogger.com,1999:blog-2933401848965498544.post-50694949166968344942011-01-21T15:24:00.000-05:002011-01-21T15:24:56.260-05:00jQuery Input Button Plugin - Iconizes Submit and Reset Buttons<a href="http://tdanryan.com/demo/jqcustomicons/demo-submitbutton.html" target="_blank">Demo</a> | <a href="http://code.msdn.microsoft.com/tdryan/Release/ProjectReleases.aspx?ReleaseId=5352" target="_blank">Source</a><br />
<br />
Last week I wrote a post on <a href="http://tdryan.blogspot.com/2011/01/jquery-ui-buttons-using-custom-icons.html" target="_blank">jQuery UI Buttons using Custom Icons</a>. As I was testing the functionality, I felt that the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a> was missing something - the ability to add icons to Submit and Reset buttons. So, I rolled my own plugin.<br />
<br />
This plugin enables adding icons to Submit and Result buttons. Behind the scenes, the plugin replaces the Submit and Reset buttons with standard button elements and then delegates the rest to the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a>.<br />
<br />
This plugin can be used just like the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a>, the only difference is the function that is invoked on the selector. <br />
<br />
To use the plugin, you need to reference all the required <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a> resources and add a reference to the jquery.inputButton.js script file (available in the <a href="http://code.msdn.microsoft.com/tdryan/Release/ProjectReleases.aspx?ReleaseId=5352" target="_blank">source</a> download). Then you would replace the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a> function attached to your selector with the inputButton function. That's quite a mouthfull, so here's a snippet.<br />
<br />
<div style="font-size: 11px;"><pre class="brush: js">$(function(){
// this will not add icons to your buttons - it will only stylize the buttons
$("input:submit:first").button({ icons: { primary: "ui-icon-disk"} });
$("input:reset:first").button({ icons: { primary: "ui-icon-refresh"} });
// this will add icons and stylize your submit and reset buttons
$("input:submit:first").inputButton({ icons: { primary: "ui-icon-disk"} });
$("input:reset:first").inputButton({ icons: { primary: "ui-icon-refresh"} });
});
</pre></div><br />
Other than that, the plugin is identical to that of the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a>.<br />
<br />
A few things to keep in mind:<br />
<ul><li>This is a proof of concept. I've tested with Chrome, Firefox, and IE 8 and it works as intended and designed.</li>
<li>Once the inputButton plugin is executed, the Submit and Reset buttons are now Button elements; therefore, all code that manipulates elements filtered on the button element (e.g. $("button")) will include the transformed Submit and Reset buttons.</li>
<li>If neither a Submit nor a Reset button is passed as the selector, the selector is passed along to the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a> - meaning the selector is handled just like any other selector by the <a href="http://jqueryui.com/demos/button/" target="_blank">jQuery UI Button widget</a>.</li>
</ul><br />
Okay, that's about it. Thanks for reading..<br />
<br />
<a href="http://tdanryan.com/demo/jqcustomicons/demo-submitbutton.html" target="_blank">Demo</a> | <a href="http://code.msdn.microsoft.com/tdryan/Release/ProjectReleases.aspx?ReleaseId=5352" target="_blank">Source</a>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-71438316028736277892011-01-14T09:44:00.002-05:002011-01-17T11:51:41.447-05:00jQuery UI Buttons using Custom Icons<a href="http://tdanryan.com/demo/jqcustomicons/demo.html" target="_blank">Demo</a> | <a href="http://code.msdn.microsoft.com/tdryan/Release/ProjectReleases.aspx?ReleaseId=5352" target="_blank">Source</a><br />
<br />
Everything jQuery rocks!<br />
<br />
<a href="http://jquery.com/">jQuery </a>makes JavaScript development enjoyable. <a href="http://jqueryui.com/">jQuery UI</a> gives us common functional components that are easy to configure and even easier to plug into our applications. <a href="http://jqueryui.com/themeroller/"> jQuery UI Themes</a> gives us the ability to stylize our applications using easy to learn conventions; furthermore, jQuery UI trivializes theme switching.<br />
<br />
So why do we need to customized our jQuery button icons? The truth is is that we probably don't; however, I tend to find myself wanting more when it comes to out-of-the-box jQuery icons.<br />
<br />
Awhile back, I created a project on <a href="http://www.codeplex.com/">CodePlex </a>for ASP.NET Web Forms called <a href="http://iconizedbutton.codeplex.com/">Iconized Control Set</a>. You can read about it <a href="http://tdryan.blogspot.com/2010/06/iconizedbutton-aspnet-control-set_15.html">here</a>, download the bits <a href="http://iconizedbutton.codeplex.com/">here</a>, and demo it <a href="http://tdanryan.com/demo/iconizedbutton/">here</a>. The following is the description from CodePlex: "ASP.NET WebForms IconizedButton Custom Control Set. Replaces the dull Button/LinkButton/HyperLink controls with styling and left and right aligned icons (via FamFamFam icon set). Contains built-in control styles/skins. Available customized user-configured styles/skins via CSS."<br />
<br />
I wanted something similar to my Iconized Control Set, yet I wanted to use it for raw HTML and possibly for <a href="http://www.asp.net/mvc">ASP.NET MVC</a>. While I plan on creating an MVC HTML Helper to abstract the details, I'm not quite ready to go down that road; however, the code here will help me create the MVC HTML Helper in due time.<br />
<br />
While I consider this a proof-of-concept, I've tested the output in FireFox, Chrome, and IE 8 and it appears to working just fine.<br />
<br />
In building the custom icon functionality for the jQuery Button, I once again relied on the excellent <a href="http://www.famfamfam.com/">FamFamFam </a>icon set. The <a href="http://www.famfamfam.com/">FamFamFam</a> icon set is not a requirement to use this customization implementation; however, I find that the FamFamFam icon set gives me what I need and then some. That said, you can certainly create your own classes and use any icons that you desire.<br />
<br />
Okay, enough background and introduction stuff.... On to the demo...<br />
<br />
Take a look at the demo <a href="http://tdanryan.com/demo/jqcustomicons/demo.html" target="_blank">here</a>.<br />
<br />
Beyond the standard<a href="http://jqueryui.com/demos/button/"> jQuery imports and configuration</a>, you will need the resources located in the code download <a href="http://code.msdn.microsoft.com/tdryan/Release/ProjectReleases.aspx?ReleaseId=5352" target="_blank">here</a>. Once you have you jQuery import and configuration set up, you will need to add the following two CSS imports to your page:<br />
<br />
<div style="font-size: 11px;"><pre class="brush: css"><link type="text/css" href="assets/css/fff.icon.core.css" rel="stylesheet"/>
<link type="text/css" href="assets/css/fff.icon.icons.css" rel="stylesheet"/>
</pre></div><br />
Once you have that, all you need to do is pass your custom icon class to the button widget function in the standard <a href="http://jqueryui.com/demos/button/">jQuery button widget implementation</a>:<br />
<br />
<div style="font-size: 11px;"><pre class="brush: js">$(function(){
$(".nav a").button({icons: {primary: "fff-icon-house-go"}});
});
</pre></div><br />
<div>Note. The demo and download both have all the custom CSS classes in one file. While this makes a demo like this easy, this file is big and is not recommended in production. Extract the icon classes that your application uses and put those classes into one of your application stylesheets.<br />
<br />
Okay, that's about it. Thanks for reading...</div>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com6tag:blogger.com,1999:blog-2933401848965498544.post-73351085410801632222011-01-08T13:43:00.001-05:002011-02-16T17:50:00.641-05:00Themed & Ajaxified MVCContrib Grid - with page size dropdown<a href="http://tdanryan.com/mvccontrib/" target="_blank">Demo</a> | <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">Source</a><br />
<br />
MVCContrib Grid. <br />
<br />
Okay, that's a little biased; however, within a couple of hours of toying around with the MVCContrib Grid, I was sold. I won't go into all the functionality provided by the grid - you can read about it <a href="http://mvccontrib.codeplex.com/wikipage?title=Grid" target="_blank">here</a>, read a more detailed writeup on Jeremy Skinner's blog <a href="http://www.jeremyskinner.co.uk/2009/02/08/rewriting-the-mvccontrib-grid/" target="_blank">here</a>, and there's a nice writeup on the use of the grid <a href="http://www.codecapers.com/post/Looking-for-an-MVC-Grid-Control-Try-MVC-Contrib!.aspx" target="_blank">here</a>. What I really like about the MVCContrib Grid is the fluent code design and GridModels. These two items are reviewed on the MVCContrib Grid page and Jeremy's posts.<br />
<br />
I'm kind of a demanding guy that is rarely satisfied. And while the MVCContrib Grid is sweet, I still wanted more. What are my demands? I use 'demands' lightly, but many people I know would disagree... I digress. Here they are:<br />
<ul><li>Themeable via <a href="http://jqueryui.com/themeroller/" target="_blank">jQuery UI Themes</a></li>
<li>AJAX enabled</li>
<li>Page Size enabled,</li>
<li>Easy to use, and</li>
<li>Easy to apply to an existing MVCContrib Grid implementation.</li>
</ul><div>The AJAX purests out there will disagree with my implementation of the AJAX functionality. I call my implementation 'poor man's AJAX.' I make the request and pass back markup. Why? Referring back to my list of 'demands'... the last two bullets are very important. I don't want fellow developers to have to learn something new - Microsoft .NET related technologies are moving at a rapid pace - there's already enough to learn - I'm writing this post on a Saturday - go away... ;-) I want the developers to make maybe a handful of simple changes to existing code and bam - it's done.</div><div><br />
</div><div>My implementation includes three parts:</div><div><ol><li>C# Class Library. A class that overrides the HtmlTableGridRenderer (HtmlTableGridThemedRenderer), a class that defines a new Pager called PagerThemed, and a couple new HTML Helper extensions.</li>
<li>A jQuery Plugin - mvccontribGrid. This plugin handles the AJAX requests and some grid stylization. This plugin works like any jQuery plugin. You pass a selector and a few options and the grid's good-to-go.</li>
<li>CSS. Simple CSS classes that provide the grid-specific styles.</li>
</ol><div>In order to use the grid, you will also need jQuery and a jQuery Theme.</div></div><div><br />
</div><div>A little word on design. I originally put all the CSS classes and selectors markup in the C# code; however, those markup features started to weigh down the AJAX response, so I moved CSS classes and selector additions to the plugin. The HtmlTableGridThemedRenderer has a method called LighenUp. This method sets an internal field that will either reduce (or not) the aforementioned CSS classes and selectors on the server-side. The default it true - meaning the CSS classes and selectors will be rendered via the jQuery plugin - client-side.</div><div><br />
</div><div>The only part of my implementation that 'smells' a bit it the requirement to have a View and a PartialView that serve almost the same function. Why does it smell? It violates DRY. However, I couldn't figure out another way to make it work without redesigning the grid control - that was not an option - I've got client work to attend to folks... :-)</div><div><br />
</div><div>Mentioning DRY, rather than cut and paste from the client (the MVC app) implementation and put it in this post, you can <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">download</a> the whole <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">source code</a> (with <a href="http://tdanryan.com/mvccontrib/" target="_blank">demo </a>code) <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">here</a>. The <a href="http://tdanryan.com/mvccontrib/" target="_blank">demo </a>code is easy to follow. Plus, I don't expend anyone to even read this post unless they have some developer knowledge and can easily figure out the simple logic. Note that the source code includes a bunch of GAC assemblies copied as local references. Since I designed the code using and for Razor (MVC 3), the GAC assemblies copied as local references was required for me to push the demo to my host - original development was <a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=955d593e-cbd1-4ed1-88eb-02ff79dd74d8" target="_blank">MVC 3 RC2</a>. You can simply remove the local assemblies and replace with you GAC assemblies.</div><div><br />
</div><div>Oh yeah, almost forgot - take a look at the <a href="http://tdanryan.com/mvccontrib/" target="_blank">demo </a>here and play around with it. Notice that the demo include the jQuery themeroller, so you can place around with the various themes available from jQuery UI.</div><div><br />
</div><div>Thanks for reading...</div><br />
References:<br />
<ul><li><a href="http://tdanryan.com/mvccontrib/" target="_blank">Demo</a></li>
<li><a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">Source</a></li>
<li><a href="http://mvccontrib.codeplex.com/" target="_blank">MVCContrib Project</a></li>
<li><a href="http://mvccontrib.codeplex.com/wikipage?title=Grid" target="_blank">MVCContrib Grid</a></li>
<li><a href="http://www.jeremyskinner.co.uk/2009/02/08/rewriting-the-mvccontrib-grid/" target="_blank">Jeremy Skinner's Blog</a></li>
<li><a href="http://jquery.com/" target="_blank">jQuery</a></li>
<li><a href="http://jqueryui.com/" target="_blank">jQuery UI</a></li>
</ul><br />
<a href="http://tdanryan.com/mvccontrib/" target="_blank">Demo</a> | <a href="http://mvcxgridmenu.codeplex.com/SourceControl/list/changesets" target="_blank">Source</a>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com8tag:blogger.com,1999:blog-2933401848965498544.post-54489340494071146812010-12-29T14:06:00.001-05:002011-01-02T18:06:53.555-05:00ASP.NET MVC 3 Custom ValidationData annotations Rock! Using data annotations on your model classes make data validation (client and server) trivial. Just add the data annotation to you model class, wire up an edit/create view to your controller via the 'Add View' wizard, and you have client- and server-side validation with very little effort.<br />
<br />
A little disclaimer here - the implementation below it not MVC 3 specific; however, I developed the solution using MVC 3, tested using MVC 3, and it works using MVC 3. I'm pretty sure it will work as-is using MVC 2.<br />
<br />
What if you need validation that is not provided via data annotations out-of-box? You create your own. That's what this post is all about.<br />
<br />
Creating your own validators that support client- and server-side validation is essentially a four-step process:<br />
<ol><li>Create a custom attribute that extends the ValidationAttribute, or better yet, you extend one of the existing data annotations.</li>
<li>Create a custom validator that extends the DataAnnotationsModelValidator<t>, where T is the type of custom attribute you created in step one.</t></li>
<li>Create a client-side script to handle the client-side validation.</li>
<li>Register the attribute/validator classes in your app's bootstrapper or Global.asax.</li>
</ol><div>Side note: It seems that every time I have a good idea for a post, Phil Haack has beat me to the punch... and this pattern is also true in this scenario :-) For a similar article on the same subject, please see Phil's<a href="http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx"> ASP.NET MVC 2 Custom Validation</a> post.<br />
<br />
This post is very code centric; therefore, if the concepts are unfamiliar or a brushing up is necessary, please take a look at Phil's <a href="http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx">post</a>. Also, Brad Wilson has a few different blog posts/series on <a href="http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html">Data Annotations</a> and <a href="http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-2-modelmetadata.html">ModelMetadata</a>. Brad and Phil's knowledge of the ins and outs of anything ASP.NET MVC (and arguably C#) scares me...</div><div><br />
</div><div>The custom attribute and validator that I'm going to create is an Email validator. There are plenty examples on the net, including <a href="http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx">here</a>, <a href="http://helios.ca/2010/02/15/asp-net-mvc-2-model-validation/">here</a>, etc... What these email validator solutions don't provide is client-side validation. I will show you how. So, lets start with step one:</div><div><br />
</div><div><span class="Apple-style-span" style="font-size: large;">1. Create a Custom Attribute</span></div><div>Below are two solutions. They both result in the same functionality. The first solution is a full implementation that extends the ValidationAttribute class, while the second solution extends the RegularExpressionAttribute.</div><div><br />
<b>EmailAttribute Extending Validation Attribute</b></div><div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Text.RegularExpressions;
namespace Validation
{
/// <summary>
/// Email Attribute class used for email validation. Used similar to the System.ComponentModel.DataAnnotations.RegularExpressionAttribute.
/// </summary>
public class EmailAttribute : ValidationAttribute
{
#region Properties
/// <summary>
/// Gets or sets the Regular expression.
/// </summary>
/// <value>The regex.</value>
private Regex Regex { get; set; }
/// <summary>
/// Gets the pattern used for email validation.
/// </summary>
/// <value>The pattern used for email validation.</value>
/// <remarks>
/// Regular Expression Source - Comparing E-mail Address Validating Regular Expressions
/// <see cref="http://fightingforalostcause.net/misc/2006/compare-email-regex.php"/>
/// </remarks>
public string Pattern
{
get
{
return
@"^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-zA-Z0-9]{1}[a-zA-Z0-9\-]{0,62}[a-zA-Z0-9]{1})|[a-zA-Z])\.)+[a-zA-Z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$";
}
}
#endregion Properties
#region Ctors
/// <summary>
/// Initializes a new instance of the <see cref="EmailAttribute"/> class.
/// </summary>
public EmailAttribute()
{
this.Regex = new Regex(this.Pattern);
}
#endregion Ctors
/// <summary>
/// Determines whether the specified value of the object is valid.
/// </summary>
/// <param name="value">The value of the object to validate.</param>
/// <returns>
/// true if the specified value is valid; otherwise, false.
/// </returns>
public override bool IsValid(object value)
{
// convert the value to a string
var stringValue = Convert.ToString(value, CultureInfo.CurrentCulture);
// automatically pass if value is null or empty. RequiredAttribute should be used to assert an empty value.
if (string.IsNullOrWhiteSpace(stringValue)) return true;
var m = Regex.Match(stringValue);
// looking for an exact match, not just a search hit.
return (m.Success && (m.Index == 0) && (m.Length == stringValue.Length));
}
}
}
</pre></div><div><br />
</div><div><b>EmailAttribute Extending RegularExpressionAttribute</b></div><div style="font-size: 11px;"><pre class="brush: csharp">using System.ComponentModel.DataAnnotations;
namespace Validation
{
/// <summary>
/// Email Attribute class used for email validation. Used similar to the System.ComponentModel.DataAnnotations.RegularExpressionAttribute.
/// </summary>
public class EmailAttribute : RegularExpressionAttribute
{
#region Ctors
/// <summary>
/// Initializes a new instance of the <see cref="EmailAttribute"/> class.
/// </summary>
public EmailAttribute()
: base(
@"^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-zA-Z0-9]{1}[a-zA-Z0-9\-]{0,62}[a-zA-Z0-9]{1})|[a-zA-Z])\.)+[a-zA-Z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$"
)
{
}
#endregion Ctors
}
}</pre></div><div>ddd<br />
Again, whatever implementation you choose is up to you. Both implementations have the same resulting functionality - Email validation via data annotations.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">2. Create a custom validator that extends the DataAnnotationsModelValidator</span><br />
This class - the validator class - is the class that provides metadata to enable client-side validation. This class essentially transfers settings, in our case the ErrorMessage and Pattern properties of the EmailAttribute class, from the attribute decorations on your model object to the client-side consumer. The client-side consumer is what provides the client-side validation.<br />
<br />
</div><div style="font-size: 11px;"><pre class="brush: csharp">using System.Collections.Generic;
using System.Web.Mvc;
using Chinook.Framework.Validation;
namespace Chinook.Web.Core.Validation
{
/// <summary>
/// Provides a model validator for the EmailAttribute annotation.
/// </summary>
public class EmailValidator : DataAnnotationsModelValidator<EmailAttribute>
{
#region Fields
private readonly string _errorMessage;
private readonly string _pattern;
#endregion Fields
#region Ctors
/// <summary>
/// Initializes a new instance of the <see cref="EmailValidator"/> class.
/// </summary>
/// <param name="metadata">The metadata.</param>
/// <param name="context">The context.</param>
/// <param name="attribute">The attribute.</param>
public EmailValidator(ModelMetadata metadata, ControllerContext context, EmailAttribute attribute)
: base(metadata, context, attribute)
{
this._errorMessage = attribute.ErrorMessage;
this._pattern = attribute.Pattern;
}
#endregion Ctors
#region Methods
/// <summary>
/// Retrieves a collection of client validation rules.
/// </summary>
/// <returns>A collection of client validation rules.</returns>
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRegexRule(this._errorMessage, this._pattern);
return new[] {rule};
}
#endregion Methods
}
}
</pre></div><div>So now that we have the attribute and validator classes created, we need to...<br />
<br />
<span class="Apple-style-span" style="font-size: large;">3. Create a client-side script to handle the client-side validation</span><br />
I feel like I'm cheating on you here. Out scenario - email validation - and it's implementation do not require us to write client-side script. I know, I know... if you feel robbed, you can create your own client-side script, and register is with the jQuery Validate plugin. I'll try and create a future post will another validator that requires writing client-side script and jQuery Validate registration, but for now we going to enjoy the luxuries of extending and using existing functionality. But, HOW do we get away with using existing client-side script?<br />
<br />
Take a look at the following code snippet from step two:</div><div style="font-size: 11px;"><pre class="brush: csharp">public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRegexRule(this._errorMessage, this._pattern);
return new[] {rule};
}
</pre></div><div><br />
This method 'retrieves' a collection of client validation rules.' And since we are essentially using a RegularExpressionAttribute class (via extension), we can use the client validation rules used by the RegularExpressionAttribute's Model Validator class via the ModelClientValidationRegexRule passing our Error Message and Regular Expression pattern.<br />
<br />
This bring us to our last step...<br />
<br />
<span class="Apple-style-span" style="font-size: large;">4. Register the attribute/validator classes in your app's bootstrapper or Global.asax</span><br />
To make all this sweetness happen, we need to register the attribute and validator classes when the app domain kicks off its like cycle. In your Global.asax's Application_Start method, register the attribue and validator classes using the following code snippet:</div><div style="font-size: 11px;"><pre class="brush: csharp">// register custom model validators
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(EmailAttribute), typeof(EmailValidator));
</pre></div><div>To use the attribute and validator classes use just created, you need to decorate you model/POCO classes with data annotations, including your EmailAttribute class. The following shows how the EmailAttribute is used (along with other data annotations) to decorated a property in your model class:</div><div style="font-size: 11px;"><pre class="brush: csharp">[Display(Name = "Email")]
[Required(ErrorMessage = "Email is Required.")]
[Email(ErrorMessage = "Not a valid Email Address.")]
[StringLength(60, ErrorMessage = "Email must be under 60 characters.")]
public string Email { get; set; }
</pre></div><div>Once you create strongly typed Edit and/or Create Views using your models, include the script libraries, and run the application, you will see the fruits of your labor and get client-side validation. The screenshot below is an example.<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrKPD9aP-W0VZB8eNeT0mI_dq8DkYDZKQ6NjpGnOUEl_el9EczjFm_tb70J05UYBfpI_2ttf2GxDINU8IkiYrYswreUhTaa6vuY53pTadIhZ8LhCC00BcWogS3XADuXBCN4H9d2r0RmHWk/s1600/emailvalidation.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrKPD9aP-W0VZB8eNeT0mI_dq8DkYDZKQ6NjpGnOUEl_el9EczjFm_tb70J05UYBfpI_2ttf2GxDINU8IkiYrYswreUhTaa6vuY53pTadIhZ8LhCC00BcWogS3XADuXBCN4H9d2r0RmHWk/s320/emailvalidation.PNG" width="320" /></a></div><br />
Anyway, I hope you got a little something out of this post.<br />
<br />
Thanks for reading...</div>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com8tag:blogger.com,1999:blog-2933401848965498544.post-38379324760540097672010-12-16T13:03:00.000-05:002010-12-16T13:03:46.491-05:00SQL Server - Get Table Dependencies via INFORMATION_SCHEMA - Template for SSMSThe following is a SQL Server script used to get a table's dependencies. The script uses SSMS template syntax, so you can add it to the SSMS Template Explorer and use the (Ctrl-Shift-M) keyboard sequence to set the script's parameters. The script returns the following for each dependency:<br />
<ul><li>Parent Table Schema Name</li>
<li>Parent Table Name</li>
<li>Parent Table Primary Key Field Name</li>
<li>Foreign Table Schema Name</li>
<li>Foreign Table Name</li>
<li>Foreign Table Foreign Key Field Name</li>
<li>Foreign Table Foreign Key Constraint Name</li>
</ul>What's nice is that the script uses INFORMATION_SCHEMA, so it may be used with other databases that support INFORMATION_SCHEMA; however, I have not tested the script with other databases. If you give the script a run on another database, I'd love to here about your experience.<br />
<div style="font-size: 11px;"><pre class="brush: sql">-- ======================================================================
-- Template used to determine a specific table's dependencies.
--
-- Use the Specify Values for Template Parameters command (Ctrl-Shift-M)
-- to fill in the parameter values below.
-- @schema_name: the schema name of the table to retrieve dependencies
-- @table_name: the table name of the table to retrieve dependencies
-- ======================================================================
DECLARE @SchemaName VARCHAR(128), @TableName VARCHAR(128);
SELECT @SchemaName = N'<schema_name, VARCHAR(128), dbo>', @TableName = N'<table_name, VARCHAR(128),>'
SELECT DISTINCT
pt.TABLE_SCHEMA AS ParentSchema,
pt.TABLE_NAME AS ParentTable,
pt.COLUMN_NAME AS ParentPrimaryField,
fk.TABLE_SCHEMA AS ForeignSchema,
fk.TABLE_NAME AS ForeignTable,
cu.COLUMN_NAME AS ForeignKeyField,
c.CONSTRAINT_NAME AS ForeignKeyConstraint
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS c
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS fk
ON c.CONSTRAINT_NAME = fk.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk
ON c.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu
ON c.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT tc.TABLE_SCHEMA,
tc.TABLE_NAME,
kcu.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
WHERE (tc.CONSTRAINT_TYPE = 'PRIMARY KEY')
) pt
ON pt.TABLE_NAME = pk.TABLE_NAME
WHERE (pk.TABLE_NAME = @TableName)
AND (pk.TABLE_SCHEMA = @SchemaName)
ORDER BY
ForeignTable ASC;
</pre></div>Thanks for reading...tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-69478181575896252212010-09-10T15:52:00.000-04:002010-09-10T15:52:53.622-04:00jQuery Theme Switcher Reset PluginUser Experience! That's what bring 'um back. Remember the first time you saw AJAX in action? Maybe it was via your GMail or Hotmail account. Whatever it was, you kept coming back to it. Why? Because it was cool; maybe because it was something that you've never seen before; or, maybe it was your fascination with 'How'd they do that?' Bottom Line: User Experience!<br />
<br />
Okay, I'll admit it - I'm not a designer! I try, and I typically come up with some good solutions; however, it takes quite awhile. Looking back at all the time I've spent making the UI look pretty, I could have added all that 'cool' functionality that the client wanted. <br />
<br />
Finding patterns that are tried and trued, well known, relatively easy to implement, predicable, and reusable is a developers dream. Unlike software development, I don't believe (well, I don't know...) that there a set of pervasive UI design patterns that all designers could pull out of their toolbox and share with other designers. I'll spare you the details, but when a developer chats with another developer common design patterns are used to communicate the intent, architecture, design, and implementation of a software component - Singleton, Repository, Decorator, etc...<br />
<br />
So, where am I going with this...? User Experience!<br />
<br />
Back to the 'cool' factor of AJAX, what else might bring back a user? What's that? A nice decision? Easy to use interface? Maybe, a UI customization feature where the user can select the way the UI is styled? That's where I'm going with this...<br />
<br />
Windows has (as far back as Windows 95 - probably farther) a function for a user to select various themes and background to change their Windows experience. iGoogle, Windows Live, and Yahoo all have theming support. Visual Studio even has theme support. <br />
<br />
<a href="http://jqueryui.com/themeroller/" target="_self">jQuery UI ThemeRoller</a> is nothing new. ThemeRoller gives you the ability to create common component themes, download the themes, and easily integrate the themes with you application/Web site. Again, this is nothing new. There is also a pluging for Firefox. A sister jQuery project is the<a href="http://jqueryui.com/docs/Theming/ThemeSwitcher"> Theme Switcher widget</a>. The ThemeSwitcher widget gives the developer the opportunity to integrate theme switching functionality into their Web site to enhance the Use Experience - there's that phrase again... The Theme Switcher is not as well known as the ThemeRoller, but it's nothing new either.<br />
<br />
What the Theme Switcher lacks is a way to integrated a custom theme that you designed and downloaded from the ThemeRoller tool. I've created a simple jQuery Theme Switcher proxy plugin that will integrate the Theme Switcher and all the outstanding jQuery UI themes with your default theme.<br />
<br />
Rather than bore you with the implementation details, you can view a demonstration here: <a href="http://tdanryan.com/demo/themeswitcherResetProxy/themeSwitcherResetProxySwing00.html">Theme Switcher Reset Proxy</a> Here's a screenshot:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzUWv6Lyw5t4oZjs8wujMLFgc9VfIJyqygHQWekNEy3j3v2P8sLBUJYqQssysSe5v-hBEva7WWz1_yMbkgOylfv6IdId5A1syWAjA9goE0ZPm23kdQ8Xx6YQQRyj4Zk4zmLcf2fklNwhkY/s1600/tsrp.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzUWv6Lyw5t4oZjs8wujMLFgc9VfIJyqygHQWekNEy3j3v2P8sLBUJYqQssysSe5v-hBEva7WWz1_yMbkgOylfv6IdId5A1syWAjA9goE0ZPm23kdQ8Xx6YQQRyj4Zk4zmLcf2fklNwhkY/s600/tsrp.PNG" /></a></div><div class="separator" style="clear: both"></div>You can download the code via View Source.<br />
Thanks for reading...tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com3tag:blogger.com,1999:blog-2933401848965498544.post-60544832333173859282010-09-02T09:07:00.000-04:002011-09-21T13:42:28.048-04:00jQuery UI Frame Dialog - Loading PaneAn updated posted is located <a href="http://tdryan.blogspot.com/2011/09/jquery-ui-frame-dialog-loading.html">here</a>. This includes modifications to the plugin to avoid multiple iFrame source loads.<br />
<br />
I like to use dialogs. Specifically, I like to use inline dialogs rendered within the current window. A popular implementation is the <a href="http://jqueryui.com/demos/dialog/" target="_blank" title="jQuery UI Dialog Widget">jQuery UI Dialog Widget</a>. I also like to render full page content in dialogs via iFrame object; however, jQuery UI Dialog Widget does not provide this functionality out-of-the-box.<br />
<br />
There is a plethora of home grown solutions for rendering iFrames wrapped within the jQuery UI Dialog Widget; however, none really fit well with what I wanted to do. That is, until I found the <a href="http://plugins.jquery.com/project/jquery-framedialog" target="_blank" title="jQuery UI Frame Dialog Plugin">jQuery UI Frame Dialog Plugin</a>. The jQuery UI Frame Dialog Plugin provides extensions to the jQuery UI Dialog Widget for rendering iFrame content. The implementation is as simple as it gets, and IMHO is the best solution for rendering iFrame content wrapped by the jQuery UI Dialog Widget.<br />
<br />
The only this missing in the jQuery UI Frame Dialog Plugin was a way to provide a loading panel (eye candy) while the iFrame's source is loading. You know the type - where an animated image is displayed while the content is acquired, loaded, and rendered and the animated image disappears when the the content is ready.<br />
<br />
I made a few modification to the jQuery UI Frame Dialog Plugin to support the loading panel concept. Essentially, I added a new property (loadingClass) to the options hash parameter. The loadingClass property is a CSS class containing styles to apply to the jQuery Dialog Widget while the iFrame's content is being acquired, loaded, and rendered. The following is an example of a CSS class used for the loadingClass parameter:<br />
<div style="font-size: 11px;">
<pre class="brush: css">.loading-image { background: transparent url('assets/im/progress-indicator-alpha.gif') no-repeat center center; }
</pre>
</div>
The following is the JavaScript used to open the dialog (initiated via an anchor):<br />
<div style="font-size: 11px;">
<pre class="brush: js">$('#dialog_link').click(function(){
var $dialog =
jQuery.FrameDialog.create({
url: 'http://espn.go.com',
loadingClass: 'loading-image',
title: 'This is the Dialog\'s Title',
width: 900,
height: 600,
autoOpen: false
});
$dialog.dialog('open');
return false;
});
</pre>
</div>
If you're interested, an online demo is located here: <a href="http://tdanryan.com/demo/framedialog/framedialogswing00.html" target="_blank" title="jQuery UI Frame Dialog with Loading Panel">jQuery UI Frame Dialog Plugin with Loading Panel</a>. The JavaScript file is accessible via View Source.<br />
<br />
I wanted to notify the developer of my addition to the jQuery UI Frame Dialog Plugin. So, I navigated to the plugin page, clicked the 'View Pending Feature Requests', successfully logged in with my account, and received the following error. The crazy thing about this error, I keep getting this error if I navigate anywhere on the Plugins site while logged in. Strange behavior! Hopefully this is a temporary issue...<br />
<br />
<div style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIuCxO3lXAbgxxeIE_0Qc4XpN63Lp65-uLEHBG-mt8PlDG0ynKaXuCtZ5l8cOkUIt950Abm1h2pR-LFZgrSudG0F0qg8d4ZM7ikePzduDzYamajqISdjl0FIXuMLUy0cukmtOLO9fh3vlR/s1600/jquerypluginaccessdenied.PNG" imageanchor="1" style="margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIuCxO3lXAbgxxeIE_0Qc4XpN63Lp65-uLEHBG-mt8PlDG0ynKaXuCtZ5l8cOkUIt950Abm1h2pR-LFZgrSudG0F0qg8d4ZM7ikePzduDzYamajqISdjl0FIXuMLUy0cukmtOLO9fh3vlR/s1600/jquerypluginaccessdenied.PNG" /></a></div>
<br />
Thanks for reading...tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com23tag:blogger.com,1999:blog-2933401848965498544.post-89378913029667190442010-08-17T15:59:00.000-04:002010-08-17T15:59:32.850-04:00C# DelegatesNice post on Action, Predicate, and Func delegates: <a href="http://blogs.vertigo.com/personal/petar/Blog/archive/2009/01/28/cool-delegates.aspx" target="_blank">Cool Delegates</a><br />
<br />
Quick Reference:<br />
<div style="font-size: 11px;"><pre class="brush: csharp">/*
* Action -
* o accepts zero or up to four parameters and returns void
* o Action :: public delegate void DelegateName()
* o Action<T> :: public delegate void DelegateName(T)
* o Action<T1, T2> :: public delegate void DelegateName(T1, T2)
* o Action<T1, T2, T3> :: public delegate void DelegateName(T1, T2, T3)
* o Action<T1, T2, T3, T4> :: public delegate void DelegateName(T1, T2, T3, T4)
*
* Predicate -
* o accepts a single parameter and returns a bool
* o Predicate<T> :: public delegate bool DelegateName(T)
*
* Func -
* o acepts zero or up to four parameters and returns any type (TResult)
* o Func<TResult> :: public delegate <TResult> DelegateName()
* o Func<T, TResult> :: public delegate <TResult> DelegateName(T1)
* o Func<T1, T2, TResult> :: public delegate <TResult> DelegateName(T1, T2)
* o Func<T1, T2, T3, TResult> :: public delegate <TResult> DelegateName(T1, T2, T3)
* o Func<T1, T2, T3, T4, TResult> :: public delegate <TResult> DelegateName(T1, T2, T3, T4)
*
*/
</pre></div>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-55819899144383136092010-08-17T13:09:00.002-04:002010-08-17T16:00:26.583-04:00System.Environment - EnvironmentList Utility ClassI'm traditionally a Web developer; however, lately I've found myself doing a bunch of console work to help automate various tasks (including work flow, file and report merging, moving builds to various environments, etc...). I've come to embrace, among many, the <a href="http://msdn.microsoft.com/en-us/library/system.io.path.aspx" target="_blank">System.IO.Path</a>, <a href="http://msdn.microsoft.com/en-us/library/system.environment.aspx" target="_blank">System.Environment</a>, and <a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx" target="_blank">System.Diagnostics.Process</a> classes. These classes help manipulate file and directory paths, provide information about means of manipulating the current environment, and access to starting and stopping local services.<br />
<br />
I often find myself investigating these class and their members and forgetting exactly what the member does. I'll locate a property or method that sounds like and is described (via comments) as something I would like to use; however, the comments are short and sweet and I must have a dozen questions pop in my mind. <em>Note to self - create a framework for interactive library documentation .</em> I digress... I'll typically create a quick console app an determine if the respective member is what I really need. This takes time - every time! So, I came up with a utility class...<br />
<br />
The following is a informational utility class that builds a collection of key: value pair of the current environment. Fundamentally, all that this class does is abstract and enumerate the various members of the System.Environment class, puts the results into a list of key: value pairs, and provides a property that exposes the results.<br />
<div style="font-size: 11px;"><pre class="brush: csharp">using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
/// <summary>
/// Environment List Class.
/// </summary>
public partial class EnvironmentList
{
#region Fields
#endregion Fields
#region Properties
/// <summary>
/// Gets the Environment Key: Value collection.
/// </summary>
/// <value>The items.</value>
public List<KeyValuePair<string, string>> Items { get; private set; }
#endregion Properties
#region Methods
/// <summary>
/// Builds the Environment dictionary/list.
/// </summary>
private void BuildDictionary()
{
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.SystemDirectory), Environment.SystemDirectory));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.CurrentDirectory), Environment.CurrentDirectory));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.MachineName), Environment.MachineName));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.OSVersion), Environment.OSVersion.ToString()));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.Version), Environment.Version.ToString()));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.UserName), Environment.UserName));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.UserDomainName), Environment.UserDomainName));
this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.ProcessorCount), Environment.ProcessorCount.ToString()));
foreach (string name in Enum.GetNames(typeof(Environment.SpecialFolder)))
this.Items.Add(new KeyValuePair<string, string>(name, Environment.GetFolderPath((Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), name))));
this.Items.Add(new KeyValuePair<string, string>("Logical Drives", string.Join("; ", Environment.GetLogicalDrives())));
ParseEnvironmentVariables(EnvironmentVariableTarget.Machine);
ParseEnvironmentVariables(EnvironmentVariableTarget.Process);
ParseEnvironmentVariables(EnvironmentVariableTarget.User);
}
/// <summary>
/// Parses the environment variables in the context of @target.
/// </summary>
/// <param name="target">The target.</param>
private void ParseEnvironmentVariables(EnvironmentVariableTarget target)
{
foreach (DictionaryEntry item in Environment.GetEnvironmentVariables(target))
{
this.Items.Add(new KeyValuePair<string, string>(item.Key.ToString(), item.Value.ToString()));
}
}
#endregion Methods
#region Event Handlers
#endregion Event Handlers
#region Ctors
/// <summary>
/// Initializes a new instance of the <see cref="EnvironmentList"/> class.
/// </summary>
public EnvironmentList()
{
this.Items = new List<KeyValuePair<string, string>>();
this.BuildDictionary();
}
#endregion Ctors
}
/// <summary>
/// Reflection Utility Class
/// <see cref="http://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/"/>
/// </summary>
public static class ReflectionUtility
{
/// <summary>
/// Gets the name of the property.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="expression">The expression.</param>
/// <returns></returns>
public static string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name;
}
}</pre></div>To use the class, instantiate the EnvironmentList object and enumerate the Items property.<br />
<br />
Console:<br />
<div style="font-size: 11px;"><pre class="brush: csharp">EnvironmentList el = new EnvironmentList();
Array.ForEach(el.Items.ToArray(), i => Console.Out.WriteLine("{0}: {1}{2}", i.Key, i.Value, Environment.NewLine));</pre></div>Web:<br />
<br />
Add a GridView to the markup and bind the grid on page load:<br />
<div style="font-size: 11px;"><pre class="brush: xml"><asp:GridView runat="server" id="gv"/></pre></div><div style="font-size: 11px;"><pre class="brush: csharp">EnvironmentList el = new EnvironmentList();
this.gv.DataSource = el.Items;
this.gv.DataBind();</pre></div>Nothing Earth shattering here, but a nice utility if you need to view the properties of the System.Environment class for the current environment.<br />
<br />
Thanks for reading...tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-87262813301652554552010-07-28T08:51:00.001-04:002010-07-28T08:53:08.640-04:00UPDATE STATISTICS for all database tables<div style="font-size: 11px;"><pre class="brush: sql">/***** BEGIN - UPDATE STATISTICS *****/
DECLARE @t TABLE(RowID INT IDENTITY(1,1), SchemaName VARCHAR(128), TableName VARCHAR(128))
INSERT INTO @t(SchemaName, TableName)
SELECT t.TABLE_SCHEMA, t.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES t
WHERE t.table_type = 'BASE TABLE'
DECLARE @Rows INT, @i INT;
SELECT @Rows = (SELECT COUNT(RowID) FROM @t), @i = 1;
WHILE(@i <= @Rows)
BEGIN
DECLARE @sqlCommand NVARCHAR(512);
SELECT @sqlCommand =
'UPDATE STATISTICS ' +
t.SchemaName + '.' +
t.TableName +
' WITH FULLSCAN'
FROM @t t
WHERE t.RowID = @i;
PRINT @sqlCommand
EXEC sp_executesql @sqlCommand;
SET @i = @i + 1;
END
GO
/***** END - UPDATE STATISTICS *****/</pre></div>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-27989886760090205072010-07-21T08:59:00.000-04:002010-07-21T08:59:16.340-04:00WCF Communications using wsHttpBinding with Username Authentication and TransportWithMessageCredentialsIt's always a good idea to secure the transport medium and require authentication when invoking Enterprise-Level Web Services. In the .NET World, these services are WCF - Windows Communications Foundation.<br />
<br />
The challenge with WCF is all the required configuration and getting it right - at least for me... Another challenge is choosing the right Authentication implementation.<br />
<br />
In my specific scenario, we have a partner system that communicates with a WCF service. The parter system is just that - a system. With respect to Authentication, you may be thinking that the obvious choice is Windows Authentication. Well, network engineers typically cringe when your requirement requires them to create Window's accounts for service-based transactions. In all fairness, creating a bunch of Windows Accounts for services can become maintenance nightmare, so I wouldn't necessarily disagree with the network engineers' concerns.<br />
<br />
So, what are the alternatives? Create you own authentication implementation? Probably not a good idea! What does ASP.NET use? That's right, ASP.NET uses the Membership Provider design pattern. Microsoft provides two two out-of-box Membership Providers: SQLMembershipProvider (SQL Server table-based accounts), and ActiveDirectoryMembershipProvider (Windows account/Active Directory). <br />
<br />
In my scenario, the ActiveDirectoryMembershipProvider presents the same challenges as Windows Authentication. My network engineers would still need to create Windows accounts. As for the SQLMembershipProvider, creating, implementing, and maintaining a SQL Server to authenticate and authorize a service request is a bit overkill (IMHO). So, what how did I ultimately implement my solution? Good question...<br />
<br />
I used a composite implementation using Microsoft's WCF Implementation Guidance How to article '<a href="http://msdn.microsoft.com/en-us/library/ff648840.aspx" target="_blank" title="WCF Implementation Guidance">How to: Use wsHttpBinding with Username Authentication and TransportWithMessageCredentials in WCF Calling from Windows Forms</a>' and the open source <a href="http://aspnetxmlproviders.codeplex.com/" target="_blank" title="ASP.NET XMLProviders">ASP.NET XMLProviders</a> project hosted on <a href="http://www.codeplex.com/" target="_blank" title="CodePlex">CodePlex</a>. I'm very happy with this implementation.<br />
<br />
Thanks for reading...tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-73588904805278281692010-06-15T15:01:00.000-04:002010-06-15T15:01:50.576-04:00Just Published The IconizedButton Control Set on CodePlexOpen the floor for criticism... I just published an open source control library on <a href="http://www.codeplex.com/">CodePlex </a>titled <a href="http://iconizedbutton.codeplex.com/">IconizedButton </a>Control Set. <a href="http://www.codeplex.com/">CodePlex </a>description: Replaces the dull Button/LinkButton/HyperLink controls with styling and left and right aligned icons (via <a href="http://www.famfamfam.com/">FamFamFam </a>icon set). Contains built-in control styles/skins. Available customized user-configured styles/skins via CSS.<br />
<br />
The <a href="http://iconizedbutton.codeplex.com/">IconizedButton </a>Control Set documentation is location <a href="http://tdryan.blogspot.com/2010/06/iconizedbutton-aspnet-control-set_15.html">here</a>.<br />
<br />
I hope someone find the control library helpful and useful.<br />
<br />
I'd appreciate any feedback you can provide.<br />
<br />
Thanks for reading...tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0tag:blogger.com,1999:blog-2933401848965498544.post-86288097126664371612010-06-15T13:57:00.001-04:002010-06-17T17:50:14.279-04:00IconizedButton ASP.NET Control Set Documentation<h3>Iconized Button Documentation</h3><h4>Contents</h4><ul><li>Summary</li>
<li>Goals</li>
<li>Features</li>
<li>Properties</li>
<li>Examples</li>
<li>Customization</li>
<li>Configuration</li>
<li>Known Issues (and Solutions)</li>
<li>Design (and Performance) Considerations</li>
<li>Credits</li>
<li>Downloads</li>
</ul><h4>Summary</h4>IconizedButton is an ASP.NET Web Forms control set providing buttons and hyperlink controls with icons and styles. IconizedButton extends the standard ASP.NET LinkButton control, while IconizedHyperLink extends the standard ASP.NET Hyperlink. Extending the standard controls makes using the IconizedButton controls painless and familiar. Use the controls as if they were the standard controls. <br />
<br />
<h4 name="ibGoals">Goals</h4><ul><li>Extend the standard ASP.NET control to include icons and skinning (without including user-defined resources);</li>
<li>no JavaScript dependencies; however, allow the user to include scripting;</li>
<li>easy deployment and integration is existing/new Web Projects;</li>
<li>light (as possible) footprint; and,</li>
<li>those features included in the 'Features' section.</li>
<li>Include text or Solo (no text) buttons</li>
</ul><h4>Features</h4><ul><li>Visual Studio Integration and Design Support</li>
<li>Buttons and hyperlinks with icons - ~ 1000 included icons (see FamFamFam in 'Credits' below) </li>
<li>Built-In Button Skinning - 20 skins</li>
<li>Button with or without text</li>
<li>Left or right align the icons (relative to the button text)</li>
</ul><h4>Properties</h4><img alt="VS Properties" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeQeBHpFTA11fsC8PbJufpoBjQSbe27y57VWyJnkgPJlrgMskRvPEmDOiiO0EmwvIFFq4MrzPmkB9buvCik2uVWHE4z1vDvo5WnJXfwToveyXDt8q1_l8WajjhqaijvrIj6pAofvxz4GVw/s800/ib_vs_properties.PNG" /><br />
<ul><li><strong>ButtonSkin : enumeration of button skins</strong> - Skin the button using one of 20 built-in skins, or set to 'Custom' and use your own via CSS. See 'Customization' section for more information on customizing the button using user-defined styles and icons.</li>
<li><strong>CustomCssClass : string</strong> - Add custom button skinning and/or additional CSS classes.</li>
<li><strong>CustomIconType : string</strong> - Set this property to your own custom icon via CSS class. IconType property must be equal to IconType.Custom or this property will be ignored.</li>
<li><strong>DisplyMouseOutStyle : boolean</strong> - Whether (or not) to display the background skin/style on mouse out - meaning no initial background and no background on mouse out. </li>
<li><strong>IconPosition : enumeration of icon positioning</strong> - Positions the icon. Enum values:<br />
<br />
<ul><li>None - no icon. Button with text only.</li>
<li>Left - left align the icon relative to the button text.</li>
<li>Right - right align the icon relative to the button text.</li>
<li>Solo - icon only button.</li>
<li>SmallSolo - icon only button with a smaller footprint than the Solo value.</li>
</ul></li>
<li><strong>IconType : enumeration of icon types - Choose from ~1000 icons to render with the button.</strong></li>
<li><strong>RoundCorners : boolean</strong> - Whether (or not) the button should render with round corners. Implemented via CSS3; therefore, no available in IE.</li>
</ul><h4>Examples</h4><ul><li>The project page on CodePlex - <a href="http://iconizedbutton.codeplex.com/" target="_blank">IconizedButton</a> - contains a sample Web application that you can download and use to test/sample the control set.</li>
<li>The following markup gives you the IconizedButton in the screenshot:<br />
<br />
<div style="font-size: 11px;"><pre class="brush: xml"><shp:IconizedButton
runat="server"
id="ibReturnHome"
Text="Return Home"
ButtonSkin="OfficeBlue"
IconPosition="Left"
IconType="HouseGo"
RoundCorners="true"
/>
</pre></div><img alt="IconizedButton Screenshot" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgTRbGWBF8cvfwLTEL3dNs3BlHnTqIJGQ5o1ZIu-NxoF2PLm6KQGRSvsmFCKprruCOJqvvS0W6zshawTyVUDZ3pREIv8NagvWmgQwqZ07ZBdn2iJ0_zFxBw8dLunzep2YhtZP9-snqic45/s800/ib_example0.PNG" /><br />
</li>
</ul><h4>Customization</h4><ul><li>The following markup gives you the customized IconizedButton in the screenshot (shout out to the troops). Custom styles and images are included in the sample Web application on <a href="http://iconizedbutton.codeplex.com/" target="_blank">CodePlex</a>.<br />
<br />
<div style="font-size: 11px;"><pre class="brush: xml"><shp:IconizedButton
runat="server"
id="ibArmyStrong"
IconType="Custom"
IconPosition="Left"
ButtonSkin="Custom"
CustomIconType="army-of-one"
CustomCssClass="army"
Text="Army Strong"
/>
</pre></div><img alt="IconizedButton Screenshot" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL6gH98uyQodvxsyw0k4mrof3479ZD054KWgilIkLGhX1i_1GHZIvqnn-VIRkBMZP_xb30mchoX08hvhxyiBg_BYZ0wpUkMahDF4dn32fZDg1Rtyaw0JVAcwBbVwnkJepoFM3eVhOfinR0/s800/ib_example1.PNG" /><br />
</li>
</ul><h4>Configuration</h4><ul><li>Toolbox - IconizedButton control set can be added to the Visual Studio Toolbox. IconButton controls have their own icons that will help identify the controls from other controls in your toolbox.<br />
<br />
<img alt="VS Toolbox" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5pnuL5aw_yo14YZ8BKYFkE8Nm0TLOtDeyZmv0dKE4v6Hbho6ZJIwRzxzOfTszxMor5MIstlYdLIHyXez0Cvhqab2H246Y33whpEEhfN7LH2sKYXHBp_PBqq4MvWsn4Rzj-tQysenCMbhN/s1600/ib_vs_toolbox.PNG" /><br />
</li>
<li>Page/User Control Registration - Dragging and dropping a control from the toolbox (like standard ASP.NET controls) will add the control to the page/user control. It will register the IconizedButton control on the top of the page/user control.</li>
<li>web.config Registration - for site/project wide registration, register the IconizedButton control set in the web.config as a child element of the <span style="font-family: Courier;"><pages><controls></controls></pages></span> element.<br />
<br />
<pre class="brush: xml"><add tagPrefix="shp" namespace="Shp.Web.UI.WebControls.Iconized" assembly="Shp.Web.UI.WebControls.Iconized"/></pre></li>
</ul><h4>Known Issues (and Solutions)</h4><ul><li>The button set controls are floated left (<span style="font-family: Courier;">float: left</span>). This means that you must clear the float in a container control. Or use a clearfix implementation - my favorite is from <a href="http://perishablepress.com/press/2009/12/06/new-clearfix-hack" target="_blank">Perishable Press</a></li>
</ul><h4>Design (and Performance) Considerations</h4><ul><li><strong>Button Skin Sprites</strong> - The button skins are image sprites. This helps minimize HTTP traffic and increases server and client performance. For more info, check this link out: <a href="http://css-tricks.com/css-sprites/" target="_blank">CSS Sprites: What They Are, Why They're Cool, and How To Use Them</a></li>
<li><strong>Icons are NOT Sprites</strong> - I created sprites for the icons categorized by alphabetical groups. While this task was tedious and time consuming, the resulting image files got a bit big for my taste (each sprite ~ 25 KB), so I decides to go with one image file per icon (~600 B). E.g. Lets say you had three iconized button on your page. The IconTypes started with 'A', 'C', and 'S' respectively. Using the sprite implementation, the resource hit would be ~ 75 KB, while using individual icon images, your resource hit would be ~ 1.8 KB. Make sense? A design decision that I didn't take lightly.</li>
<li><strong>No JavaScript</strong> - One of my goals was to have no JavaScript dependencies. Understanding that the .NET Framework will add JavaScript to perform PostBacks, validations, etc..., IconizedButton control set adds no additional JavaScript resources. This also helps when the user/developer wants to customize the buttons an not have to hack around JavaScript dependencies. Just use the buttons (and additional JavaScript) as you would use LinkButton and HyperLink controls.</li>
<li><strong>Visual Studio Designer</strong> - Selecting an IconType will display a default icon for the control. During the IconizedButton control set development, rendering the icon associated with the IconType gave me the infamous Visual Studio design-time delay. The design time delay (the pause in Visual Studio while it retrieves, processes, and renders a resource) is probably my biggest gripe with Visual Studio. I love the IDE; however, this really annoys me. Rendering only a default icon at design-time significantly improves design-time performance.</li>
</ul><h4>Credits</h4><ul><li>The icons are designed, developed, and licensed by Mark James of <a href="http://www.famfamfam.com/" target="_blank">FamFamFam</a>. The specific FamFamFam library of icons used in the IconizedButton control set is the <a href="http://www.famfamfam.com/lab/icons/silk/" target="_blank">Silk Icon</a> set. If you need icons for your application, check out FamFamFam. FamFamFam icons are licensed under the <a href="http://creativecommons.org/licenses/by/3.0/" target="_blank">Creative Commons Attribution 3.0 License</a>.</li>
</ul><h4>Downloads</h4><ul><li><a href="http://iconizedbutton.codeplex.com/releases" target="_blank">Binary</a></li>
<li><a href="http://iconizedbutton.codeplex.com/releases" target="_blank">Sample Web Application</a></li>
<li><a href="http://iconizedbutton.codeplex.com/SourceControl/list/changesets" target="_blank">Source</a></li>
</ul>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com1tag:blogger.com,1999:blog-2933401848965498544.post-22962443948631690552010-06-11T15:16:00.001-04:002010-06-11T15:19:33.421-04:00Test code for my previous post <a href="http://tdryan.blogspot.com/2010/06/telerik-radwindow-client-side-content.html">Telerik RadWindow Client-Side Content Container</a>. Sorry, the formatting is a little off.<br />
CSS:<br />
<div style="font-size: 11px;"><pre class="brush: css">ul#actionList, ul#actionList li {margin: 0; padding: 0; list-style: none; line-height: 20px;}
ul#actionList { margin: 5px 10px; } ul#actionList li { margin-bottom: 5px; }
div#echoConsole { margin: 20px; border: 1px solid #ababab; background-color: #fbfec2; padding: 5px; }
p { padding: 5px; margin: 0; font-family: Arial; font-size: 12px; }
.mar-b-10 {margin-bottom: 10px;}
</pre></div>JavaScript:<br />
<div style="font-size: 11px;"><pre class="brush: js">$(document).ready(function() {
// attach the click event to the buttons - button will open the new RadWindow dialog
$('ul#actionList button').click(function(e) {
e.preventDefault();
var btnID = $(this).get(0).id;
switch (parseInt(btnID.substring(btnID.length - 1))) {
case 0:
radWindowExtensions.openDialog({ width: 400, height: 400, title: 'This is the Dialog Title', content: $('div#hiddenDiv'), resizable: false, onOpen: dialogHandlers.onOpen, onClosing: dialogHandlers.onClosing, onClosed: dialogHandlers.onClosed });
break;
case 1:
radWindowExtensions.openDialog({ width: 500, height: 600, title: 'This is the Dialog Title', content: $('div#hiddenDiv').html(), resizable: true, onOpen: dialogHandlers.onOpen, onClosing: dialogHandlers.onClosing, onClosed: dialogHandlers.onClosed });
break;
case 2:
radWindowExtensions.openDialog({ xPos: '100', yPos: 10, onOpen: dialogHandlers.onOpen, onClosing: dialogHandlers.onClosing, onClosed: dialogHandlers.onClosed });
break;
case 3:
radWindowExtensions.openDialog();
break;
}
});
});
// test handlers object - will echo event handler messages to a div tag
var dialogHandlers = {
_getConsole: function() { if (!dialogHandlers._console) { dialogHandlers._console = $('div#echoConsole').show(); } return dialogHandlers._console; },
_echo: function(msg) { var c = dialogHandlers._getConsole(); c.append($('<div/>').addClass('mar-b-10').html(msg)); },
onOpen: function(content) {
// use onOpen event handler to modify the content - e.g. add event handlers to buttons, etc...
dialogHandlers._echo('onOpen event fired on RadWindow with ID of ' + this.get_name());
$(content).find('p:first').css('color', 'red');
},
onClosing: function(content) {
// use onClosing event handler to clean up content - e.g. unbind event handlers.
dialogHandlers._echo('onClosing event fired on RadWindow with ID of ' + this.get_name());
dialogHandlers._echo('number of paragraphs: ' + $(content).find('p').size());
},
onClosed: function(content) {
dialogHandlers._echo('onClosed event fired on RadWindow with ID of ' + this.get_name());
dialogHandlers._echo('number of paragraphs: ' + $(content).find('p').size());
}
};
</pre></div>HTML:<br />
<div style="font-size: 11px;"><pre class="brush: html"><ul id="actionList"><li> <button id="btnDialog0">Show Dialog</button> Content set to a jQuery wrapped object, non-resizable </li>
<li> <button id="btnDialog1">Show Dialog</button> Content set to HTML </li>
<li> <button id="btnDialog2">Show Dialog</button> No Content, positioned dialog </li>
<li> <button id="btnDialog3">Show Dialog</button> No Content, no options (default) dialog </li>
</ul><div id="echoConsole" style="display: none;"></div><div style="display: none;"><div id="hiddenDiv"><div>Morbi scelerisque urna aliquam sapien dictum eget lacinia justo eleifend. Morbi eu nibh nibh? Morbi non justo id magna fermentum accumsan.
Donec nunc mi, facilisis a venenatis eu, congue in ligula? Praesent nisl turpis, aliquet vitae eleifend non, auctor id erat. Nam a
felis ac mauris ornare lacinia. Cras a massa sit amet leo tempor tincidunt.
Curabitur pellentesque enim id est porta ornare. Morbi orci leo, sodales et lobortis vel, egestas at magna. Nam a nisi odio, suscipit
ullamcorper quam. Pellentesque ullamcorper est vel quam blandit vel laoreet libero euismod. Nam orci sem, condimentum id interdum
feugiat, laoreet nec mi. Duis varius cursus dolor id porttitor.
Nulla id ligula sit amet leo imperdiet sollicitudin. Donec pulvinar, sem quis condimentum pellentesque, orci nisl placerat tellus,
at egestas ante arcu nec lectus. Nullam cursus porta molestie. Sed in auctor metus. Cum sociis natoque penatibus et magnis dis parturient
montes, nascetur ridiculus mus. Fusce volutpat vestibulum erat quis ultrices.
</div></div></div></pre></div>tdryanhttp://www.blogger.com/profile/17038688255673658684noreply@blogger.com0