<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8338234734413867615</id><updated>2011-12-27T21:26:30.427-08:00</updated><category term='LightSwitch'/><title type='text'>Common Knowledge</title><subtitle type='html'>Reflections, commentary, and tips on software development.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-8741298701915424655</id><published>2011-10-04T14:50:00.000-07:00</published><updated>2011-10-04T14:52:52.416-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LightSwitch'/><title type='text'>Adding the Full Name Property to User Lists</title><content type='html'>My &lt;a href="http://traf-o-data.blogspot.com/2011/08/linking-lightswitch-data-to-logged-in.html"&gt;earlier post about linking data to the LightSwitch user list&lt;/a&gt; has turned out to me my most popular yet. In fact, I've actually used this technique for the 2nd time in project and wound up using my own blog as a reference implementation! In my latest project I added feature that will probably prove useful to anyone using this technique: the addition of the &lt;i&gt;Full Name&lt;/i&gt; property. This is a profile property that LightSwitch adds to users in the membership provider that is not part of the standard user properties.&lt;br /&gt;&lt;br /&gt;Adding the Full Name property is pretty easy. First, of course, you have to add a FullName property to the Data Transfer Object (DTO):&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; User&lt;br /&gt;    {&lt;br /&gt;        [Key]&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Guid UserId { get; set; }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UserName { get; set; }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FullName { get; set; }&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;Next, we have to populate the FullName value from the profile properties. This part involves working with the ASP.Net Profile interface, which is more obscure that the main Membership interface:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;var userList = Membership.GetAllUsers();&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MembershipUser user &lt;span class="kwrd"&gt;in&lt;/span&gt; userList)&lt;br /&gt;    {&lt;br /&gt;        var returnUser = &lt;span class="kwrd"&gt;new&lt;/span&gt; User &lt;br /&gt;        { &lt;br /&gt;            UserId = (Guid)user.ProviderUserKey, &lt;br /&gt;            UserName = user.UserName &lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        &lt;span class="rem"&gt;//create a profile object to query&lt;/span&gt;&lt;br /&gt;        var profile = ProfileBase.Create(user.UserName);&lt;br /&gt;&lt;br /&gt;        &lt;span class="rem"&gt;//look up the LightSwitch FullName property in the profile&lt;/span&gt;&lt;br /&gt;        returnUser.FullName = profile.GetPropertyValue(&lt;span class="str"&gt;"FullName"&lt;/span&gt;).ToString();&lt;br /&gt;&lt;br /&gt;        returnValue.Add(returnUser);&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;In order to understand how this code fits in with the overall service, please refer to &lt;a href="http://traf-o-data.blogspot.com/2011/08/linking-lightswitch-data-to-logged-in.html"&gt;my earlier post&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Adding the FullName property will allow you to display the full user name that you entered using the LightSwitch user manager, so you won't have to remember user names to identify users of your application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-8741298701915424655?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/8741298701915424655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=8741298701915424655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/8741298701915424655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/8741298701915424655'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2011/10/adding-full-name-property-to-user-lists.html' title='Adding the Full Name Property to User Lists'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-8160058208996221911</id><published>2011-09-09T13:10:00.000-07:00</published><updated>2011-09-09T13:10:58.351-07:00</updated><title type='text'>A Spoonful of Syntactic Sugar</title><content type='html'>One of the reasons I love developing with C# is the ease with which you can extend the language using facilities like generics,&amp;nbsp;extension&amp;nbsp;methods, and lambda expressions. As an old C++ coder, I feel very comfortable with a bizarre level of language extensiblity. Here's an example of what I'm talking about:&lt;br /&gt;&lt;br /&gt;I was writing a library that scans an XML element tree, and I kept having the need to cast down from an XMLNode to an XMLElement. Naturally, to avoid runtime errors, I had to check the cast for success. The code looked something like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;    foreach&lt;/span&gt; (var node &lt;span class="kwrd"&gt;in&lt;/span&gt; parentElement.ChildNodes)&lt;br /&gt;    {&lt;br /&gt;        var element = node &lt;span class="kwrd"&gt;as&lt;/span&gt; XmlElement;&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (element != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;        {&lt;br /&gt;            ProcessElement(element);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After a while, this got pretty tiresome. I even started omitting the check for success out of fatigue, which of course led to run-time errors. Something had to be done! Fortunately C# provided a way to address this problem. I created the following extension method:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;    public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ExecByType&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;delegate&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DoOp&amp;lt;T&amp;gt;(T t);&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IfType&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; T t, DoOp&amp;lt;T&amp;gt; d)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt;(t != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            {&lt;br /&gt;                d(t);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This allowed me to change the code to something like this:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var node &lt;span class="kwrd"&gt;in&lt;/span&gt; parentElement.ChildNodes)&lt;br /&gt;    {&lt;br /&gt;        (node &lt;span class="kwrd"&gt;as&lt;/span&gt; XmlElement).IfType(e =&amp;gt; ProcessElement(e));&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Which not only prevented errors, it also looks kind of exciting, so it's helping keep me awake while I finish my XML processing routines.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-8160058208996221911?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/8160058208996221911/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=8160058208996221911' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/8160058208996221911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/8160058208996221911'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2011/09/spoonful-of-syntactic-sugar.html' title='A Spoonful of Syntactic Sugar'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-2883315421418622451</id><published>2011-08-31T14:38:00.000-07:00</published><updated>2011-08-31T14:38:58.215-07:00</updated><title type='text'>Adding Passwords to a WCF Service</title><content type='html'>I recently set up a WCF service that required password protection, with user accounts and passwords synchronized with an ASP.NET site using the standard ASP.NET Membership provider. I found several books and a number of blogs that gave helpful examples, but ultimately I felt that I never found the one, single, go-to example that just focused on the topic of adding username and password support in WCF. So this is my humble attempt at a stripped down, laser focused tutorial on the subject.&lt;br /&gt;&lt;h2&gt;Prerequisites&lt;/h2&gt;Here is a prioritized checklist for your implementation:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Understand that you &lt;i&gt;will &lt;/i&gt;need SSL. WCF will not allow you to add username/password authentication to a service unless it is encrypted at the transport layer; this means that you must use the HTTPS protocol and you must obtain an SSL certificate. For those of you who are students or cheapskates, it is possible to &lt;a href="http://www.clintharris.net/2009/self-signed-certificates/"&gt;generate a self signed SSL certificate&lt;/a&gt;. If you're a professional developer with control of your own DNS domain, I recommend that you think about just getting a real trusted certificate for your test server. Given the low cost of a certificate from a trusted authority, this can wind up saving time and therefore money in the long run. In any case, don't even think about proceeding until you've taken care of this issue.&lt;/li&gt;&lt;li&gt;Use the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;basicHttpBinding&lt;/span&gt;. The default binding for a WCF service application in Visual Studio is the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;wsHttpBinding&lt;/span&gt;. If you use the ws binding and add passwords, you get a session based protocol in which the client and server first negotiate a shared secret, then use the shared secret to sign all subsequent messages. This is a triumph of technology and generally not a problem if you can be absolutely sure that only .NET programmers will access your service. However, the minute a PHP, Rails, Java, or Phython team tries to work with your service you'll get an earful: it can be very challenging to set up session based WS authentication with these frameworks. On the other hand, if you use the basic binding, you'll get stateless authentication that behaves much closer to expectations and is much easier to implement on other platforms.&lt;/li&gt;&lt;li&gt;Make sure you understand how the ASP.NET membership service is configured. Both the membership and role providers should have configuration elements in your web.config file (don't rely on the default configuration). Take note of the &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.security.membership.applicationname.aspx"&gt;applicationName&lt;/a&gt;&amp;nbsp;configuration attribute and its function (short story: it is possible for multiple user name directories to coexist in the same database using different application names). The main point is: if you want your service to synchronize with a website, but the service is not directly a part of that website, you must make sure that both the membership connection string and the application names match.&lt;/li&gt;&lt;/ol&gt;Now that we've got the preliminaries out of the way, all we need is the configuration file, right? After all, can't all WCF issues be solved in the configuration file? With that in mind, I've prepared a stripped down&amp;nbsp;configuration&amp;nbsp;that contains only what you need to enable the ASP.NET membership passwords for a WCF service:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;code&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;connectionStrings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_CONNECTION_STRING"&lt;/span&gt;&lt;br /&gt;         &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="ToDo: put a valid connection string here"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;connectionStrings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.web&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;compilation&lt;/span&gt; &lt;span class="attr"&gt;debug&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;targetFramework&lt;/span&gt;&lt;span class="kwrd"&gt;="4.0"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;&amp;lt;!-- this is the standard role and membership configuration&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        that might already be present in your web.config if&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        the local ASP.NET site is using the membership&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        framework for page access--&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;roleManager&lt;/span&gt; &lt;span class="attr"&gt;defaultProvider&lt;/span&gt;&lt;span class="kwrd"&gt;="AspNetRoleProvider"&lt;/span&gt; &lt;br /&gt;                 &lt;span class="attr"&gt;enabled&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;providers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;clear&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="AspNetRoleProvider"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.Security.SqlRoleProvider"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;connectionStringName&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_CONNECTION_STRING"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;applicationName&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_APPLICATION_NAME"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;providers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;roleManager&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;membership&lt;/span&gt; &lt;span class="attr"&gt;defaultProvider&lt;/span&gt;&lt;span class="kwrd"&gt;="AspNetMembershipProvider"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;providers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;clear&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="AspNetMembershipProvider"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.Security.SqlMembershipProvider"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;connectionStringName&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_CONNECTION_STRING"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;applicationName&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_APPLICATION_NAME"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;providers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;membership&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.web&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;behaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceBehaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;behavior&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="rem"&gt;&amp;lt;!-- no need for http get;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;              but https get exposes endpoint over SSL/TLS--&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceMetadata&lt;/span&gt; &lt;span class="attr"&gt;httpGetEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;="false"&lt;/span&gt; &lt;span class="attr"&gt;httpsGetEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="rem"&gt;&amp;lt;!-- the authorization and credentials elements tie&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;            this behavior (defined as the default behavior) to&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;            the ASP.NET membership framework--&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceAuthorization&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;principalPermissionMode&lt;/span&gt;&lt;span class="kwrd"&gt;="UseAspNetRoles"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;roleProviderName&lt;/span&gt;&lt;span class="kwrd"&gt;="AspNetRoleProvider"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceCredentials&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;userNameAuthentication&lt;/span&gt;&lt;br /&gt;                &lt;span class="attr"&gt;userNamePasswordValidationMode&lt;/span&gt;&lt;span class="kwrd"&gt;="MembershipProvider"&lt;/span&gt;&lt;br /&gt;                &lt;span class="attr"&gt;membershipProviderName&lt;/span&gt;&lt;span class="kwrd"&gt;="AspNetMembershipProvider"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;serviceCredentials&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;behavior&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;serviceBehaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;behaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;bindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;&amp;lt;!-- this binding configuration stipulates that a&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;          user name and password are required--&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;basicHttpBinding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt; &lt;span class="attr"&gt;mode&lt;/span&gt;&lt;span class="kwrd"&gt;="TransportWithMessageCredential"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;message&lt;/span&gt; &lt;span class="attr"&gt;clientCredentialType&lt;/span&gt;&lt;span class="kwrd"&gt;="UserName"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;basicHttpBinding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;bindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceHostingEnvironment&lt;/span&gt; &lt;span class="attr"&gt;multipleSiteBindingsEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;&amp;lt;!-- in this very simple example we're relying on default &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        binding configuration, behavior, and endpoints--&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_NAMESPACE.YOUR_SERVICE"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt; &lt;span class="attr"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;="basicHttpBinding"&lt;/span&gt; &lt;br /&gt;                  &lt;span class="attr"&gt;contract&lt;/span&gt;&lt;span class="kwrd"&gt;="YOUR_NAMESPACE.I_YOUR_SERVICE"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;There's lot's more to say about this topic, including how to use role assignments to authorize service access, but hopefully this will be enough to get you started.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-2883315421418622451?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/2883315421418622451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=2883315421418622451' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/2883315421418622451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/2883315421418622451'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2011/08/adding-passwords-to-wcf-service.html' title='Adding Passwords to a WCF Service'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-1734148933995421851</id><published>2011-08-03T18:20:00.000-07:00</published><updated>2011-10-04T14:52:27.016-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LightSwitch'/><title type='text'>Linking LightSwitch Data to Logged in Users</title><content type='html'>Note: if you like this post be sure to take a look at my &lt;a href="http://traf-o-data.blogspot.com/2011/10/adding-full-name-property-to-user-lists.html"&gt;October 4th post&lt;/a&gt; that contains an enhancement to this technique.&lt;br /&gt;&lt;br /&gt;In my presentation LightSwitch in Context (which I will be presenting on Wednesday, September 28 at the &lt;a href="http://www.meetup.com/The-San-Francisco-NET-User-Group/"&gt;Bay Area Database Developers .NET User Group&lt;/a&gt;) I demonstrate how LightSwitch can be used to create an administrative interface for a public facing website. In one part of the demo, I create a RIA service that can be used to query for a list of users from the .NET Membership service. I am starting to realize that this little trick can be quite handy, and I've already used in a paying project for a client. It is also a good demonstration of how easy it is to create a RIA service for a read-only data source that is outside of the normal scope of your application. RIA services can be intimidating, but if you know the right steps to follow they can be blown out in a few minutes using Visual Studio templates.&lt;br /&gt;&lt;br /&gt;Here's how to create a RIA service that allows access to the current list of users in your application. Note that this only works if your using Forms authentication, i.e. the ASP.NET Membership provider. If you are using Windows authentication, you can do something similar but you'll have to replace the Membership code with calls to Active Directory. Also, this requires the full (Professional or better) version of Visual Studio; you can't create data extensions like this with the standard edition of LightSwitch.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Step 1: Add a WCF RIA Services Class Library to your project&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;With your LightSwitch application is open in Visual Studio, right-click the Solution icon and select Add-&amp;gt;New Project... from the context menu. This will bring up the New Project dialog. Select template type Silverlight, then WCF RIA Service Class Library:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-UMgXRzt0Yv8/TjnnS58b7wI/AAAAAAAAAFY/M4iB1eYVAZ8/s1600/RIA+Service+Project.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="344" src="http://1.bp.blogspot.com/-UMgXRzt0Yv8/TjnnS58b7wI/AAAAAAAAAFY/M4iB1eYVAZ8/s640/RIA+Service+Project.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;You can see that I'm calling my project &lt;i&gt;UserDataService&lt;/i&gt;. After you add the project, you will see that template adds not one but two projects to your solution. One will be called UserDataService and one will be called UserDataService.Web. Since this blog is not discussing the fine points of RIA Services, the only thing you need to know is that you can ignore the UserDataService project completely, we'll be working only with UserDataService.Web.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Step 2: Add Membership Provider Assemblies&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;By default a RIA Services library doesn't have references to the library that implement the ASP.NET membership services. So you'll need to add the following references to the UserDataService.Web project:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;System.Web&lt;/li&gt;&lt;li&gt;System.Web.ApplicationServices&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;b&gt;&lt;u&gt;Step 3: Define Your User Entity&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In order to send a user list back to LightSwitch as a table, you'll need to define a Data Transfer Object (DTO) that will hold data about an individual user. The properties of the DTO will depend on what properties of the user you are interested in. In this example, we're sticking just to the login name:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.ComponentModel.DataAnnotations;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; UserDataService.Web&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; User&lt;br /&gt;    {&lt;br /&gt;        [Key]&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; Guid UserId { get; set; }&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UserName { get; set; }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Note that we are including the Guid that is used by the Membership framework to uniquely identify users and marking this as the key to the entity. In general, you will always want to define a key for your DTOs.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Step 4: Create The Service&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Now it's time to create the service itself. Right-click the UserDataService.Web icon and select&lt;i&gt; Add-&amp;gt;New Item..&lt;/i&gt; from the context menu. In the&lt;i&gt; Add New Item&lt;/i&gt; dialog, select template type Web, and Domain Service Class template:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-OWTXIr-9A7c/TjnrDxrxNpI/AAAAAAAAAFc/4mB4hbzHlYU/s1600/RIA+Service+Class.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="344" src="http://1.bp.blogspot.com/-OWTXIr-9A7c/TjnrDxrxNpI/AAAAAAAAAFc/4mB4hbzHlYU/s640/RIA+Service+Class.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;In this screenshot, I'm calling my class &lt;i&gt;UserService&lt;/i&gt;, however in the example below, I'm using &lt;i&gt;UserData &lt;/i&gt;as a class name. Now we get to the fun part, where we actually have to write some code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web.Security;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserData : DomainService&lt;br /&gt;{&lt;br /&gt;    [Query(IsDefault = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IQueryable&amp;lt;User&amp;gt; GetUsers()&lt;br /&gt;    {&lt;br /&gt;        var returnValue = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;User&amp;gt;();&lt;br /&gt;&lt;br /&gt;&lt;span class="preproc"&gt;#if&lt;/span&gt; DEBUG&lt;br /&gt;        returnValue.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; User &lt;br /&gt;        {&lt;br /&gt;            UserId = &lt;span class="kwrd"&gt;new&lt;/span&gt; Guid(&lt;span class="str"&gt;"{1F43C32F-D6E3-4CCE-A4A0-7BB9D7572C07}"&lt;/span&gt;), &lt;br /&gt;            UserName = &lt;span class="str"&gt;"Tom"&lt;/span&gt;&lt;br /&gt;        });&lt;br /&gt;&lt;br /&gt;        returnValue.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; User &lt;br /&gt;        {&lt;br /&gt;            UserId = &lt;span class="kwrd"&gt;new&lt;/span&gt; Guid(&lt;span class="str"&gt;"{F4D71F57-2CD1-4C60-B9BE-FA2529A9EE2D}"&lt;/span&gt;), &lt;br /&gt;            UserName = &lt;span class="str"&gt;"Dick"&lt;/span&gt;&lt;br /&gt;        });&lt;br /&gt;        returnValue.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; User &lt;br /&gt;        {&lt;br /&gt;            UserId = &lt;span class="kwrd"&gt;new&lt;/span&gt; Guid(&lt;span class="str"&gt;"{8FF1E47C-BA41-4586-8D23-A3079850FDAA}"&lt;/span&gt;), &lt;br /&gt;            UserName = &lt;span class="str"&gt;"Harry"&lt;/span&gt;&lt;br /&gt;        });&lt;br /&gt;&lt;span class="preproc"&gt;#else&lt;/span&gt;&lt;br /&gt;        var userList = Membership.GetAllUsers();&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (MembershipUser user &lt;span class="kwrd"&gt;in&lt;/span&gt; userList)&lt;br /&gt;        {&lt;br /&gt;            returnValue.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; User &lt;br /&gt;            { &lt;br /&gt;                UserId = (Guid)user.ProviderUserKey, &lt;br /&gt;                UserName = user.UserName &lt;br /&gt;            });&lt;br /&gt;        }&lt;br /&gt;&lt;span class="preproc"&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; returnValue.AsQueryable();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Here are a couple of things to note:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The Query attribute marks this method as an RIA service method that returns a queryable entity container.&lt;/li&gt;&lt;li&gt;The basic structure of the code, in which you return a list of entities that you want to appear as a table, is extremely simple. You can use this same technique for any kind of data that you want to return as a read-only list.&lt;/li&gt;&lt;li&gt;I've put a DEBUG condition in to populate my list with pretend users. This is important because LightSwitch in debug mode, with Forms authentication enabled, will have a valid Membership provider but won't have any actual users.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;Step 5: Add the Service to LightSwitch&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After you've rebuild your solution to set up the data service (important!), you are ready to add the service as a data source. Right-click on the Data Sources folder in LightSwitch, and select Add Data Source from the context menu. Then, select WCF RIA Service, click Next, then Add Reference, then select the Project tab. You want to add a reference to UserDataService.Web. Then you will be able to select your entity call User. This is a lot of wizard screens, but it goes pretty fast if you've set everthing up according to the instructions above. When you are done, a Users table will appear in LightSwitch, which looks something like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-QnvCXAs8UmE/TjnuHmW7KBI/AAAAAAAAAFg/6AR-18LELXQ/s1600/Success.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-QnvCXAs8UmE/TjnuHmW7KBI/AAAAAAAAAFg/6AR-18LELXQ/s1600/Success.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;b&gt;&lt;u&gt;Step 6: Link the User Data to LightSwitch tables&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Now that the Users table exists in LightSwitch, you can link other tables from your main data source. This is slightly different that creating a relationship within the main data source, because you have to create a foreign key in the linked table yourself. Recall that we're using a Guid as a key, so we'll want the foreign key to also be a Guid. In this example I'm linking to the &lt;i&gt;SalesPersons &lt;/i&gt;table, so I want to create a new column call &lt;i&gt;Login &lt;/i&gt;in &lt;i&gt;SalesPersons &lt;/i&gt;of type Guid. Here's what the relationship dialog looks like when the relationship is set:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-G77bh0-ZfvM/TjnvU0Qmg1I/AAAAAAAAAFk/Jd_LcgOxsd0/s1600/Relationship.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/-G77bh0-ZfvM/TjnvU0Qmg1I/AAAAAAAAAFk/Jd_LcgOxsd0/s400/Relationship.png" width="302" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now that you've got the data linked, the RIA service data can be used just like any other LightSwitch data. This screen shot shows the selector that is automatically generated for you when the User link is formatted as an Auto Complete Box:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Ke0JHAzGjE8/TjnwZbrmQzI/AAAAAAAAAFo/jC8keGdUezk/s1600/DropDown.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="286" src="http://4.bp.blogspot.com/-Ke0JHAzGjE8/TjnwZbrmQzI/AAAAAAAAAFo/jC8keGdUezk/s320/DropDown.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Hopefully this simple example will get you started with RIA Services extensions. They're not as bad as they look, and when you need 'em, you need 'em.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-1734148933995421851?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/1734148933995421851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=1734148933995421851' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/1734148933995421851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/1734148933995421851'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2011/08/linking-lightswitch-data-to-logged-in.html' title='Linking LightSwitch Data to Logged in Users'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-UMgXRzt0Yv8/TjnnS58b7wI/AAAAAAAAAFY/M4iB1eYVAZ8/s72-c/RIA+Service+Project.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-6284528031017462133</id><published>2011-04-22T16:40:00.000-07:00</published><updated>2011-08-30T13:29:09.066-07:00</updated><title type='text'>Transferring a Database to SQL Azure: The Magic Handshake</title><content type='html'>&lt;i&gt;Update 8/30/2011: I'm leaving this post as-is for reference; however please be aware that the best way to transfer a database to SQL Azure is to use the &lt;a href="http://sqlazuremw.codeplex.com/"&gt;SQL Azure Migration Wizard&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Transferring an existing SQL Server database to SQL Azure can be very easy if you know the right tools and one essential configuration detail, or what I like to call, "the magic handshake." SQL Azure is still near the bleeding edge, and if you get some bad advice you could spend hours on this. Here's a quick rundown on how to do it the easy way.&lt;br /&gt;&lt;h2&gt;The Magic Handshake&lt;/h2&gt;There are several ways to get your database up to a SQL Azure instance, but the most painless is the &lt;a href="http://msdn.microsoft.com/en-us/library/ms140052.aspx"&gt;SQL &amp;nbsp;Import and Export Wizard.&lt;/a&gt;&amp;nbsp;However, if you don't know the magic handshake, your experience goes something like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;You start up the Import and Export Wizard, either from the start menu or from SQL Management Studio. You make sure to use the SQL Server 2008 R2 version, because you know that plain old SQL Server 2008 can't talk to Azure.&lt;/li&gt;&lt;li&gt;You set your source data to the database you want to export to Azure.&lt;/li&gt;&lt;li&gt;When setting your destination, for some reason you can't log in to your Azure instance. Undaunted, you do some quick Googling (with Bing, of course) and find out that you have to include the full name to your server in your user name, e.g. Bullwinkle@reallyweirdname.database.windows.net. With that change you actually log in. And you can select the target Azure database! The excitement is building now! With a tremendous sense of anticipation, you click &lt;i&gt;Next&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Boom! you're out of luck:&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-qUnIEj6_5GM/TbILyT067AI/AAAAAAAAAE8/6fp6jjD9Zas/s1600/AzureUploadError.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-qUnIEj6_5GM/TbILyT067AI/AAAAAAAAAE8/6fp6jjD9Zas/s1600/AzureUploadError.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The wizard says it, "cannot get the supported data types from the database connection," and that, "the stored procedure required to complete this operation could not be found on the server." But what it should have said is, "you didn't give me the magic handshake."&lt;br /&gt;&lt;br /&gt;So what is the magic handshake? It happens back at step 2. You have to select &lt;b&gt;.Net Framework Data Provider for SqlServer&lt;/b&gt; for your destination. This will give you a distinctly non-wizard like settings screen:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-n7fZpMM4Lko/TbINTTcYg4I/AAAAAAAAAFA/ElzezHkQ3D8/s1600/FramerworkDPSettings.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="400" src="http://2.bp.blogspot.com/-n7fZpMM4Lko/TbINTTcYg4I/AAAAAAAAAFA/ElzezHkQ3D8/s400/FramerworkDPSettings.jpg" width="391" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Does this look like a wizard to you?&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;But it's pretty simple: just fill out the Data Source, Initial Catalog, User ID, and Password the same as you would in a connection string. Also, you can use the simple User ID without the @server suffix. Click &lt;i&gt;Next &lt;/i&gt;again and you're off to the races!&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Azure Compatibility&lt;/h2&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;If your database is simple enough, you may not need to make any changes to your schema. In fact, I would recommend that unless you know you're schema is too clever, go ahead and grind through the Import and Export Wizard steps I've outlined above. If you have any Azure&amp;nbsp;computability&amp;nbsp;problems, you'll get detailed error messages from the wizard.&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;If you do get errors, then you won't be able to let the wizard create your tables for you. That means you'll have to script the database schema first and correct the errors that were mentioned in the import error dialog. For example, Azure doesn't like tables that don't have any clustered indexes defined. To fix this, just change the primary key on each table from non-clustered to clustered, run the creation scrip in your Azure DB, then run the Import/Export wizard. It will pick up on the existing tables and use them instead of trying to create new tables for the import.&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;I decided to write a post on this because there doesn't seem to be a lot of good information available on migrating SQL Server databases to Azure. Now that I've been through the process, it seems very simple. That is, once I learned the magic handshake.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-6284528031017462133?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/6284528031017462133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=6284528031017462133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/6284528031017462133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/6284528031017462133'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2011/04/transferring-database-to-sql-azure.html' title='Transferring a Database to SQL Azure: The Magic Handshake'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-qUnIEj6_5GM/TbILyT067AI/AAAAAAAAAE8/6fp6jjD9Zas/s72-c/AzureUploadError.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-5291197874126048282</id><published>2011-01-30T22:37:00.000-08:00</published><updated>2011-01-30T22:37:57.388-08:00</updated><title type='text'>The Incredible Lightness of ELMAH</title><content type='html'>I recently gave a &lt;a href="http://en.wikipedia.org/wiki/Lightning_Talk"&gt;lightning talk&lt;/a&gt; at the San Francisco Bay.NET User Group meeting on ELMAH (Error Logging Modules and Handlers). This was a great opportunity to learn about this tool, which was originally developed by &lt;a href="http://scottonwriting.net/sowBlog/"&gt;Scott Mitchell&lt;/a&gt; and &lt;a href="http://www.raboof.com/"&gt;Atif Aziz&lt;/a&gt; as sample code for an MSDN article. Since the initial release in 2004, Atif Aziz has been continuing development and maintenance on ELMAH &amp;nbsp;as a&amp;nbsp;community&amp;nbsp;open source project.&lt;br /&gt;&lt;br /&gt;I've been aware of ELMAH for some time, but I hadn't gotten around to really looking at it; I'm very glad that the &lt;a href="http://www.clear-lines.com/blog/"&gt;Mathias Brandewinder&lt;/a&gt;, the Bay.NET Chapter Leader for San Francisco, asked me to give the lighting talk. It gave me a chance to roll up my sleeves and get to know this great resource for ASP.NET development.&lt;br /&gt;&lt;br /&gt;ELMAH is a good topic for a quick demonstration, because the setup is so easy. All you need to set up an error log is to download ELMAH, put the ELMAH dll in the bin folder of your site, and make a few additions to your web config file. One line must be added to the httpHandlers section:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;lt;httpHandlers&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;add verb="POST,GET,HEAD"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;path="elmah.axd"&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;type="Elmah.ErrorLogPageFactory, Elmah" /&amp;gt;&lt;br /&gt;&amp;lt;/httpHandlers&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and one to the httpModules section:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;httpModules&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;add name="ErrorLog" &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;type="Elmah.ErrorLogModule, Elmah" /&amp;gt;&lt;br /&gt;&amp;lt;/httpModules&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;If you're running IIS 7, you'll have to also make module and handler entries in the system.webServer section:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; &amp;lt;system.webServer&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;modules runAllManagedModulesForAllRequests="true"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;lt;add name="ErrorLog"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;type="Elmah.ErrorLogModule, Elmah" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;/modules&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;handlers&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;lt;add name="Elmah"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;preCondition="integratedMode"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;verb="POST,GET,HEAD"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;path="elmah.axd"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;type="Elmah.ErrorLogPageFactory, Elmah"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;/handlers&amp;gt;&lt;br /&gt;&amp;lt;/system.webServer&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The amazing thing about ELMAH is that once you make these changes, you'll have a fully functional error log. You get to the error log by entering the path to your handler (I've just left the handler path at the default "elmah.axd" in the examples above). Here's what you see:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Qirob5Z12CY/TUZPeAsDkvI/AAAAAAAAAE0/wTtA87h4Nio/s1600/ElmahMainPage.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="285" src="http://3.bp.blogspot.com/_Qirob5Z12CY/TUZPeAsDkvI/AAAAAAAAAE0/wTtA87h4Nio/s640/ElmahMainPage.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;This example contains only a single error, but as you can see the display&amp;nbsp;accommodates&amp;nbsp;multiple errors with paging options. Clicking on the details tab shows a stack trace, error details, and a full dump of the HTTP request attributes.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;The only other essential item in setting up a basic ELMAH installation is to set up a data store for errors. The display shown above is using the in-memory log, which means errors will be lost when the server is reset. Adding a data store means that error will persist after a reboot. ELMAH supports multiple database platforms; I set mine up with SQL server, which looks something like this:&lt;/div&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;configSections&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;sectionGroup name="elmah"&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;lt;section name="errorLog"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;requirePermission="false"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;type="Elmah.ErrorLogSectionHandler, Elmah" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;/sectionGroup&amp;gt;&lt;br /&gt;&amp;lt;/configSections&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;elmah&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;lt;errorLog type="Elmah.SqlErrorLog, Elmah" &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;code&gt;connectionString="Data Source=YourDatabaseServer;Initial&amp;nbsp;&lt;/code&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;Catalog=YourDatabase;Trusted_Connection=True" /&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;code&gt; &amp;lt;/elmah&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;There are many more capabilities of ELMAH, including email notification and error filtering. You can learn about them at the &lt;a href="http://code.google.com/p/elmah/"&gt;official project site&lt;/a&gt;. It is a good idea to look at the security setup information on the project site to make sure your error handler is secure.&lt;/div&gt;&lt;h2&gt;What I Learned&lt;/h2&gt;&lt;div&gt;I have my own&amp;nbsp;philosophy&amp;nbsp;about error handling architectures which I've developed over many projects, but working with ELMAH showed me a new approach. Instead of requiring conformance to a particular error handling and reporting strategy in code, ELMAH treats error handling as a cross-cutting concern and handles errors &lt;i&gt;transparently&lt;/i&gt;. This means there is no requirement to build error handling into your code at all, making the code more portable and eliminating any problems with inconsistent implementation. For more on this topic, I encourage you to read &lt;a href="http://msdn.microsoft.com/en-us/library/aa479332.aspx"&gt;the original MSDN article&lt;/a&gt; for which ELMAH was created.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-5291197874126048282?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/5291197874126048282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=5291197874126048282' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/5291197874126048282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/5291197874126048282'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2011/01/incredible-lightness-of-elmah.html' title='The Incredible Lightness of ELMAH'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_Qirob5Z12CY/TUZPeAsDkvI/AAAAAAAAAE0/wTtA87h4Nio/s72-c/ElmahMainPage.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-1495405329333462292</id><published>2010-10-29T13:20:00.000-07:00</published><updated>2010-10-29T13:20:51.445-07:00</updated><title type='text'>The Mystery of mscorlib</title><content type='html'>I had an interesting problem recently while converting a Visual Studio 2008 project to Visual Studio 2010. This was a solution that included a website project and a number of library projects (side note: I don't recommend website projects, try web application projects instead). The website project and all of the library projects targeted the .NET 3.5 framework. The Reason I was converting this project was just to use the new features of VS 2010; I didn't want to go through a full conversion of the project to .NET 4.0 because that would have meant testing and deployment time I didn't have. So when the framework warning dialog appeared:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Qirob5Z12CY/TMsYQew595I/AAAAAAAAAEM/9dbJd03yISE/s1600/UpgradeWarning.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="135" src="http://4.bp.blogspot.com/_Qirob5Z12CY/TMsYQew595I/AAAAAAAAAEM/9dbJd03yISE/s400/UpgradeWarning.jpg" width="400" /&gt;&amp;nbsp;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I clicked, "No." So far so good.&lt;br /&gt;&lt;br /&gt;But now I had a problem. When I rebuilt the project, I saw the following error:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;The primary reference &lt;path assembly="" my="" to=""&gt; could not be resolved because it has an indirect dependency on the .NET Framework assembly "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" which has a higher version "4.0.0.0" than the version "2.0.0.0" in the current target framework.&lt;br /&gt;&lt;/path&gt;&lt;/code&gt;&lt;br /&gt;Huh? I understand that it's not a good idea to mix 2.0 and 4.0 assemblies, but I hadn't asked for any links to the 4.0 runtime. The reference to version 2.0 is confusing, until you reflect on the fact that a project targeting 3.5 is actually using version 2.0 of the core framework. That's why it's so easy to upgrade project from 2.0 to 3.5. But where did the .NET 4.0 reference come from? A little more investigation revealed that reference was embedded in just 1 of the library projects. I was able to build this project successfully, but when I did I got some strange errors, such as:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Warning 5 The predefined type 'System.Action' is defined in multiple assemblies in the global alias; using definition from 'c:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;So it looked like the 4.0 library was being used, but why, and why wasn't I able to see this anywhere in the project configuration information? The property pages for the project showed that it was targeting framework version 3.5. When I looked at the assembly references for the project, I couldn't see any reference to mscorlib, either 2.0 or 4.0:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Qirob5Z12CY/TMsb7unn9TI/AAAAAAAAAEQ/0iWB1yRJDQs/s1600/VSReferences.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_Qirob5Z12CY/TMsb7unn9TI/AAAAAAAAAEQ/0iWB1yRJDQs/s1600/VSReferences.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This got me thinking: I knew that mscorlib is the assembly that contains the core implementation of the .NET framework, so why don't we see it in the Visual Studio reference list? Apparently the VS team thinks it's none of our business. Fortunately we don't have to be limited by this restriction - I loaded up &lt;a href="http://www.red-gate.com/products/reflector/"&gt;Redgate Reflector&lt;/a&gt; and found the complete list of references for this assembly:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_Qirob5Z12CY/TMse8hx_xxI/AAAAAAAAAEU/fuG5ejyMfts/s1600/Reflector.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_Qirob5Z12CY/TMse8hx_xxI/AAAAAAAAAEU/fuG5ejyMfts/s1600/Reflector.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Now we're getting somewhere! We can see both mscorlib references and we can see that one reference is to the 4.0 version of .NET. Comparing this display to the Visual Studio version, we can see that VS represents the mscorlib assembly with logical references that don't exactly match the assembly references. Is this a good thing? I would say no. My view is: when you are looking at the reference list, you really are looking for assemblies, not logical namespaces. Also, obscuring the mscorlib assembly in the reference list is not consistent with the way other assemblies are displayed.&lt;br /&gt;&lt;br /&gt;Back to our problem: how do we eliminate this phantom 4.0 reference? For the solution I relied on my old friend Subversion version control. I ran a diff on the projects that converted successfully and compared those to a diff on the project with the .NET 4.0 reference. It turned out that the library with the .NET 4.0 reference had been completely skipped during the upgrade process for some reason. I was able to fix the problem by merging the diffs from the successfully converted files into the problem project by hand. I found that the key problem was at the top of the project file. I replaced this heading:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="2.0"&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;with this heading:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;And added this section to the PropertyGroup element:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;oldtoolsversion&amp;gt;2.0&amp;lt;/oldtoolsversion&amp;gt;&lt;br /&gt;&amp;lt;upgradebackuplocation&amp;gt;&lt;br /&gt;&amp;lt;/upgradebackuplocation&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;There were also some discrepancies with assembly references, but I found that when I merged the entries shown above the assembly references took care of themselves with a rebuild, and the rogue reference to mscorlib version 4.0 had been purged.&lt;br /&gt;&lt;br /&gt;So I learned something about mscorlib, and as is so often the case the learning experience involved some frustration. The account in this blog post omits many of the detours I took while investigating this problem. I hope posting my results here I might save others from spending too much time on this. Remember: ignore mscorlib at your peril!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-1495405329333462292?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/1495405329333462292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=1495405329333462292' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/1495405329333462292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/1495405329333462292'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2010/10/mystery-of-mscorlib.html' title='The Mystery of mscorlib'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Qirob5Z12CY/TMsYQew595I/AAAAAAAAAEM/9dbJd03yISE/s72-c/UpgradeWarning.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-3336286607910358781</id><published>2010-04-29T10:13:00.000-07:00</published><updated>2010-04-29T10:13:10.308-07:00</updated><title type='text'>Is Custom Development OK Again?</title><content type='html'>I was very interested to see &lt;a href="http://www.drdobbs.com/architecture-and-http://www.drdobbs.com/architecture-and-design/224600606" target="_blank"&gt;Mike Jones’s article in Dr. Dobbs&lt;/a&gt; about the current state of  custom software development.&amp;nbsp; Here are my thoughts on the subject:&lt;br /&gt;&lt;br /&gt;During the 1990's there was an irrational commitment to custom development as  a strategic asset. Due to the state of development platforms at the time and  very high expectations, many projects failed to deliver on the promise of  business value and of course most failed to stay on budget (we're talking  software, after all).  &lt;br /&gt;&lt;br /&gt;Around the turn of the century, there was a sea change and since then we've  been living with the backlash against past excess: over the last decade there  has been an irrational aversion to custom development at all levels. Ironically,  advances in methodology (primarily Agile) and also the maturity of development  platforms and technology stacks has led to a dramatic increases in the  productivity and effectiveness of custom development teams. The $1 million  custom project of 1998 now cost $30K, and, unlike 1998, it actually works!  &lt;br /&gt;&lt;br /&gt;What I would like to see is a balance assessment of custom development’s  potential. If we can achieve this, I think we'll see an important role for  custom work going forward.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-3336286607910358781?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/3336286607910358781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=3336286607910358781' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/3336286607910358781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/3336286607910358781'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2010/04/is-custom-development-ok-again.html' title='Is Custom Development OK Again?'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-928637718784030167</id><published>2010-02-25T09:45:00.000-08:00</published><updated>2010-02-25T09:45:43.578-08:00</updated><title type='text'>Secure automatic updates</title><content type='html'>Over the last month or so, I've update the Flash player on several of my workstations several times. &amp;nbsp;Each time I do this, there's one little detail that gets my goat: the executable file that actually does the updating isn't digitally signed. &amp;nbsp;Here's how the Flash updates sequence plays out:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The Flash update warning appears automatically when I log in. &amp;nbsp;I try to distrust everything that happens; how do I know this is really a Flash update? But I figure, let's see where this goes.&lt;/li&gt;&lt;li&gt;I get a UAC flash. &amp;nbsp;I know that some people don't like UAC, but I love it. &amp;nbsp;I want to know when an application starts messing with my system settings.&lt;/li&gt;&lt;li&gt;The UAC warning is telling me that there's an app call "flashupdate2.exe" that's trying to change my system settings.&lt;/li&gt;&lt;li&gt;Here's the problem: flashupdate2.exe isn't digitally signed. &amp;nbsp;That means there's no way to verify what it really is and where it came from.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;At this point I have a choice: either don't update my Flash player, leaving me vulnerable to known attacks, or bet that the application that says it's a Flash updater really is a Flash updater and not a malware trojan.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Oh, that's right. &amp;nbsp;There is a 3rd alternative: uninstall Flash until Adobe decides to&amp;nbsp;exercise&amp;nbsp;some common sense and sign their application updates for the benefit of everyone's security.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-928637718784030167?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/928637718784030167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=928637718784030167' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/928637718784030167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/928637718784030167'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2010/02/secure-automatic-updates.html' title='Secure automatic updates'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-6310089313351119088</id><published>2009-11-29T11:12:00.000-08:00</published><updated>2009-11-29T11:12:17.912-08:00</updated><title type='text'>Mea Culpa</title><content type='html'>I've spend the last year completing a major update of the &lt;a href="http://www.cooksf.com/"&gt;Cook! SF web site&lt;/a&gt;.  In the process I've had to come to grips with my fear of Javascript and I've become much more aware of the amazing things that are being done using web standards based presentation.  So perhaps I've greatly exaggerated the death of HTML.&lt;br /&gt;&lt;br /&gt;The lesson I'm taking from this is not just that HTML is not in any way doomed, but more importantly that the Internet never has been, and never will be, just one thing. &amp;nbsp;So Flash will continue to be increase in popularity, Silverlight adoption will proceed apace, and so will mobile platforms and everything else, including plain old HTML and &amp;nbsp;Javascript.&lt;br /&gt;&lt;br /&gt;Please disregard that last post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-6310089313351119088?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/6310089313351119088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=6310089313351119088' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/6310089313351119088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/6310089313351119088'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2009/11/mea-culpa.html' title='Mea Culpa'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-8837648297014353099</id><published>2009-01-11T21:46:00.001-08:00</published><updated>2009-01-11T21:46:23.729-08:00</updated><title type='text'>AJAX and the Pony Express</title><content type='html'>&lt;p&gt;I sometimes teach classes at &lt;a href="http://www.academyx.com/" target="_blank"&gt;AcademyX&lt;/a&gt;, and by luck the San Francisco campus of AcademyX is located within walking distance of my office on Market St.&amp;#160; On my way to class, I often pass a collection of commemorative placards that mark the site of the old western terminus of the Pony Express on Clay St. between Kearny and Montgomery.&amp;#160; Many people have heard of the Pony Express: a heroic enterprise in which mail pouches where carried over the Rocky Mountain West in a tightly scripted relay of horses and riders.&amp;#160; Deliveries could make it from Missouri to California in just 10 days, which a very good time for horse and rider.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Qirob5Z12CY/SWrZKW5DqbI/AAAAAAAAAB8/vJU9ebogo3U/s1600-h/1936%20Plac%20Reduced%5B7%5D.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; margin: 0px 10px 0px 0px; border-left: 0px; border-bottom: 0px" height="484" alt="Pony Express Placard on Clay St." src="http://lh5.ggpht.com/_Qirob5Z12CY/SWrZLc_ZzVI/AAAAAAAAACA/p7vB-XwkxKs/1936%20Plac%20Reduced_thumb%5B5%5D.jpg?imgmax=800" width="287" align="left" border="0" /&gt;&lt;/a&gt;One surprising fact about the Pony Express is that it lasted less than a year as a going concern.&amp;#160; But Pony Express couriers are still galloping through the American imagination; even today the Pony Express emblem is used by the U.S. Post office.&lt;/p&gt;  &lt;p&gt;It was technology that killed the Pony Express: the service was discontinued shortly after completion of the transcontinental telegraph.&amp;#160; This is a familiar story to those of us who've been following digital technology for very long.&amp;#160; Ingenuity, planning, and perspiration won't make the grade if you're competing against a superior platform.&amp;#160; With just a flick of the wrist, a telegraph operator could beat a team of Pony Express riders and their carefully build infrastructure of relay stations.&amp;#160; This got me thinking: could it be that Asynchronous JavaScript And XML (a.k.a. AJAX) will face the same fate as the Pony Express?&lt;/p&gt;  &lt;p&gt;The role of the transcontinental telegraph in this story will be played by Rich Internet Applications (RIAs).&amp;#160; RIAs have actually been around since before AJAX, but they have been slow to catch on compared to the wildfire acceptance of AJAX among web developers.&amp;#160; But there can be no doubt that RIAs are catching on.&amp;#160; Flex has clearly had blockbuster success recently, and both Silverlight and JavaFX are waiting in the wings.&lt;/p&gt;  &lt;p&gt;Now that AJAX interfaces are common on the web, the limitations of this architecture are becoming clear.&amp;#160; It's common for AJAX pages to become unresponsive when something goes wrong with a script based postback.&amp;#160; Error handling is a problem; most browsers have JavaScript error reporting turned off by default because errors are so frequent.&amp;#160; Last year I was blown away and frankly shocked by &lt;a href="http://www.holub.com/" target="_blank"&gt;Alan Holub's&lt;/a&gt; presentation about the security problems associated with AJAX.&amp;#160; Most importantly, from a developer's perspective, AJAX can be a lot of work.&amp;#160; Of course there are frameworks that make simple and common effects easy to achieve.&amp;#160; But frameworks require debugging and customization: ultimately there's no escape from the complexity of the architecture.&lt;/p&gt;  &lt;p&gt;Ultimately the advantage of an RIA platform is simplicity.&amp;#160; An RIA application is what it is: a stateful, sandboxed, and media rich application that can be scripted to respond to user interaction.&amp;#160; In fact, we can drop the &amp;quot;scripting&amp;quot;, RIAs run compiled code, just like a decent programming environment.&amp;#160; An AJAX web application only &lt;em&gt;appears&lt;/em&gt; to be these things.&amp;#160; There is no simplicity, even in the simplest AJAX enabled page.&lt;/p&gt;  &lt;p&gt;As a programmer, what would you rather do: spend a few hours in a single development environment putting together an application with data binding, full user interaction, and some neat animations, or spend several days making an AJAX-enabled web page behave as if it were an RIA?&amp;#160; If you chose the AJAX path, you might just be as heroic as the Pony Express rider of old, doing the impossible with stout ponies, wits, and willpower.&amp;#160; No doubt you'll have some adventures along the way.&amp;#160; When you get to town, you'll find me a the telegraph office.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-8837648297014353099?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/8837648297014353099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=8837648297014353099' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/8837648297014353099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/8837648297014353099'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2009/01/ajax-and-pony-express.html' title='AJAX and the Pony Express'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Qirob5Z12CY/SWrZLc_ZzVI/AAAAAAAAACA/p7vB-XwkxKs/s72-c/1936%20Plac%20Reduced_thumb%5B5%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8338234734413867615.post-99771922641908245</id><published>2008-11-10T23:17:00.001-08:00</published><updated>2008-11-10T23:17:30.162-08:00</updated><title type='text'>Adaptive Connection Strings for Windows Forms Applications</title><content type='html'>&lt;p&gt;As a developer working with small businesses, I do a lot of Windows Forms based development.&amp;#160; One of the great things about this platform is the ease of deployment.&amp;#160; A traditional installation program can be created in a matter of minutes.&amp;#160; Better yet, with one-click deployment it's easy to update a client's machine at a remote location with the touch of a button.&lt;/p&gt;  &lt;p&gt;In a small-scale custom development context, it's very common that simple updates are urgently needed.&amp;#160; This could be because of an undiscovered bug, but more commonly it is the result of an unknown or poorly understood business rule that emerges at the worst possible moment.&amp;#160; For example, during invoicing it is discovered that no one told the developer about new discount rules.&amp;#160; In this scenario a simple fix at the code level is usually possible, and extensive acceptance testing is counterproductive.&amp;#160; This is where quick and easy deployment makes everyone's life easier.&lt;/p&gt;  &lt;p&gt;But there is one fly in the deployment ointment: the database connection string for the production environment is always different than the development environment.&amp;#160; That means that the last step in any deployment is resetting the database connection string.&amp;#160; There are several problems with this, including:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;If you forget to change the connection or make a mistake in resetting the string, your already cranky client gets an immediate connection error after the deployment. &lt;/li&gt;    &lt;li&gt;There's no obvious automatic way to make sure you don't make a mistake when you reset the string. &lt;/li&gt;    &lt;li&gt;There's no way to test within the development environment to make sure you've got the production connection right.&amp;#160; If you develop this way, every build you deploy is in fact an untested build, because it can't run successfully in the development testing environment. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;What we really need is an application feature that will manage the connection string for us, that will make sure the correct connection string is always used.&amp;#160; It must be possible to set up the connection configuration once, test it in all environments, and then leave it alone.&amp;#160; This would allow us to deploy our changes without any changes to the connection string.&amp;#160; The feature should be valid for both application assemblies and DLLs that are deployed as components.&amp;#160; I call this feature, &amp;quot;Adaptive Connection Strings&amp;quot; and the rest of this post describes how to make it happen.&lt;/p&gt;  &lt;h3&gt;Getting Control of the Connection String&lt;/h3&gt;  &lt;p&gt;Almost all useful business applications have at least one database connection.&amp;#160; Whether you're using hand-coded ADO.NET Connection objects, table adapters, LINQ to SQL, or the ADO.NET Entity Framework to connect to your database, the most convenient and flexible option for managing database connection strings is to create connection string setting in the application settings class.&amp;#160; Visual Studio designers do this for you when you choose the &lt;em&gt;save this connection&lt;/em&gt; option. But application settings of type connection string are always application level read-only properties, so it is not possible to build run-time logic to modify them.&lt;/p&gt;  &lt;p&gt;But are connection string properties really read only?&amp;#160; Let's take a quick look at a connection string property definition in the Settings.Designer.cs class:&lt;/p&gt; &lt;code&gt;   &lt;blockquote&gt;     &lt;p&gt;public string MyAppConnectionString {        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; get {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; return ((string)(this[&amp;quot;MyAppConnectionString&amp;quot;]));         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }         &lt;br /&gt;} &lt;/p&gt;   &lt;/blockquote&gt; &lt;/code&gt;  &lt;p&gt;You can see that the property is clearly defined as read only.&amp;#160; But you can also see that the connection string property is really just an alias for a call to a indexer defined by the settings class.&amp;#160; The indexer used here is defined in System.Configuration.ApplicationSettingsBase to provide a reference to the Properties member collection.&amp;#160; It turns out that all application settings are accessible in read/write mode by using this indexer directly.&amp;#160; The following code demonstrates how to modify the connection string using this approach:&lt;/p&gt;  &lt;blockquote&gt;&lt;code&gt;     &lt;p&gt;//change the application connection string        &lt;br /&gt;Properties.Settings.Default[&amp;quot;MyAppConnectionString&amp;quot;] = strCnString; &lt;/p&gt;      &lt;p&gt;//debug:verify that this really did work        &lt;br /&gt;Console.WriteLine(Properties.Settings.Default.MyAppConnectionString);&lt;/p&gt;   &lt;/code&gt;&lt;/blockquote&gt;  &lt;p&gt;So we can set up the connection string at run time, as long as we have an effective place to put this code.&amp;#160; For example, we could put this in the constructor of the main form of an application.&amp;#160; But how do we determine which connection string to use?&lt;/p&gt;  &lt;h3&gt;Finding the Right Connection&lt;/h3&gt;  &lt;p&gt;The whole point of this technique is to make the connection adaptive; we want the application database connection to automatically adapt based on the context in which it is running.&amp;#160; This can be done in a number of different ways, but in most cases you will find the Environment class very helpful.&amp;#160; The static instance of this class can be used to collect information about the host of the current process.&amp;#160; I usually use the MachineName property to identify development workstations.&amp;#160; The code looks something like this:&lt;/p&gt;  &lt;blockquote&gt;&lt;code&gt;     &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; string ServerName;        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; string DatabaseName; &lt;/p&gt;      &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; switch (System.Environment.MachineName)        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; case &amp;quot;DEV1&amp;quot;:         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; case &amp;quot;DEV2&amp;quot;:         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ServerName = @&amp;quot;DEV\SQL2008&amp;quot;;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DatabaseName = &amp;quot;Test&amp;quot;;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; break; &lt;/p&gt;      &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; default:        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ServerName = @&amp;quot;CONTOSO\BIGBOY&amp;quot;;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; DatabaseName = &amp;quot;Production&amp;quot;;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; break;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; } &lt;/p&gt;      &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; System.Data.SqlClient.SqlConnectionStringBuilder bld        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; = new System.Data.SqlClient.SqlConnectionStringBuilder(); &lt;/p&gt;      &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; bld.DataSource = ServerName;        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; bld.InitialCatalog = DatabaseName;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; bld.IntegratedSecurity = true; &lt;/p&gt;      &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Properties.Settings.Default[&amp;quot;MyAppConnectionString&amp;quot;] = bld.ConnectionString;        &lt;br /&gt;&lt;/p&gt;   &lt;/code&gt;&lt;/blockquote&gt;  &lt;p&gt;This approach works well in small scale settings when you can be sure that there won't be duplicate machine names in different domains.&amp;#160; For a more scalable approach, you can also parse the domain name from the UserDomainName property of the static Environment instance.&lt;/p&gt;  &lt;p&gt;At this point we're in pretty good shape.&amp;#160; We have a way to control the connection string at runtime, and we have a programmatic method to determine which connection string to use.&amp;#160; But that still leaves one important issue: we don't have a standard way to include this code in our projects that will guarantee the connection will be initialized before any data components are constructed.&amp;#160; For example, if we are building a DLL that exposes multiple public methods, there is no single entry point at which we can perform the initialization.&amp;#160; Wouldn't it be nice if we could simply handle a &amp;quot;load&amp;quot; event for the assembly settings?&amp;#160; It turns out that we can do that, and use the same technique whether we are building a stand-alone application or component.&lt;/p&gt;  &lt;h3&gt;Hooking Settings Initialization&lt;/h3&gt;  &lt;p&gt;In order to hook the load event for your assembly settings, you must first create a code behind file for the settings class.&amp;#160; To do this, select &lt;em&gt;&amp;lt;app name&amp;gt; properties&lt;/em&gt; from the &lt;em&gt;Project&lt;/em&gt; menu in Visual Studio, then click the settings tab.&amp;#160; This is the same screen that is used to modify connection string properties:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Qirob5Z12CY/SRkxhkCi4xI/AAAAAAAAABQ/oZkOP7XAomw/s1600-h/image33.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="339" alt="The project settings screen" src="http://lh3.ggpht.com/_Qirob5Z12CY/SRkxiPZhjrI/AAAAAAAAABY/7OdPZyGDD8c/image3_thumb2.png?imgmax=800" width="598" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note the &lt;em&gt;View Code&lt;/em&gt; button, which is highlighted by the red circle.&amp;#160; When this button is clicked, Visual Studio creates a Settings.cs file in the main directory of your application (you would expect this file to appear in the Properties directory, but it goes into the main directory instead).&lt;/p&gt;  &lt;p&gt;When this file is created, it contains two pre-wired events: SettingChanging and SettingsSaving.&amp;#160; These events are of no use for our purposes.&amp;#160; In order to hook the SettingsLoaded event, you must manually add an event handler, as shown below:&lt;/p&gt;  &lt;blockquote&gt;&lt;code&gt;     &lt;p&gt;public Settings() {        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; //         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // To add event handlers for saving and changing settings,         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // uncomment the lines below:         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; //         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // this.SettingChanging += this.SettingChangingEventHandler;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; //         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // this.SettingsSaving += this.SettingsSavingEventHandler;         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // &lt;/p&gt;      &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;this.SettingsLoaded +=          &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; new System.Configuration.SettingsLoadedEventHandler(Settings_SettingsLoaded);&lt;/strong&gt;         &lt;br /&gt;} &lt;/p&gt;      &lt;p&gt;void Settings_SettingsLoaded(object sender,        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; System.Configuration.SettingsLoadedEventArgs e)         &lt;br /&gt;{         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // Connection string initialization goes here         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; // ...         &lt;br /&gt;} &lt;/p&gt;   &lt;/code&gt;&lt;/blockquote&gt;  &lt;p&gt;You can now move the connection string setting code into the SettingsLoaded event.&amp;#160; Since you are in the code behind file for the settings class, you can replace references to Properties.Settings.Default with the &lt;em&gt;this&lt;/em&gt; keyword:&lt;/p&gt;  &lt;blockquote&gt;&lt;code&gt;     &lt;p&gt;this[&amp;quot;MyAppConnectionString&amp;quot;] = bld.ConnectionString; &lt;/p&gt;   &lt;/code&gt;&lt;/blockquote&gt;  &lt;p&gt;The connection string initialization is a good candidate for a code snippet.&amp;#160; In most cases the only difference in this code from project to project will be the server and database settings.&lt;/p&gt;  &lt;p&gt;It should be noted that if you're using SQL Server Authentication or another connection type that requires a user name and password, you won't want to hook the SettingsLoaded event.&amp;#160; In this case, you'll have to display a login dialog to retrieve the authentication information.&amp;#160; But you'll still be able to use the technique described above to control the connection string properties of your application.&lt;/p&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;This post demonstrates a technique for adaptive connections strings that can be used for all Windows Forms application and component projects.&amp;#160; I've used this technique at my company, PJPM, to deploy patches and updates to clients very quickly and easily.&amp;#160; It definitely takes an important pain point out of the deployment process.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8338234734413867615-99771922641908245?l=traf-o-data.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://traf-o-data.blogspot.com/feeds/99771922641908245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8338234734413867615&amp;postID=99771922641908245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/99771922641908245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8338234734413867615/posts/default/99771922641908245'/><link rel='alternate' type='text/html' href='http://traf-o-data.blogspot.com/2008/11/adaptive-connection-strings-for-windows.html' title='Adaptive Connection Strings for Windows Forms Applications'/><author><name>Paul Keister</name><uri>http://www.blogger.com/profile/03500839803346226676</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://2.bp.blogspot.com/_Qirob5Z12CY/SRk2MUWtGrI/AAAAAAAAABk/JVOJejb3vMs/S220/Celebrity+Paul.bmp'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Qirob5Z12CY/SRkxiPZhjrI/AAAAAAAAABY/7OdPZyGDD8c/s72-c/image3_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
