Accessing the Membership Provider from Silverlight

by mgordon 13. May 2009 04:50

In a particular Silverlight application, I felt it would be common for a user to have the application open for long periods, but not necessarily be interacting with it all the time.  This meant that there was always a chance the user’s session would time out.  Since the application uses the Membership and Role providers, nasty errors were being raised from web service calls depending on data from these providers if the session was not available.

To handle this situation, I tested for a valid session in my services and raised a custom exception if it wasn’t available.  Then, using the ideas in my last post I trapped that exception in my Silverlight application and showed a login box to the user so they could log back into the application and re-establish a valid session.

The next piece of this puzzle to solve was how to gain access to the Membership Provider from the Silverlight application to log the user back in.  Turns out there are two ways to go and both are equally valid for an Ajax application as well as Silverlight, though one is clearly more suitable for Ajax than Silverlight.

ASP.Net Ajax

The first solution is to use functionality built into the ASP.Net Ajax framework.  There is a javascript object in the framework, Sys.Services.AuthenticationService, that provides the needed functionality.  So, if you have all the necessary parts of the Ajax framework set up, in JavaScript you can say

var ssa = Sys.Services.AuthenticationService;

ssa.login(username,
              password,
              isPersistent,
              customInfo,
              redirectUrl,
              onLoginComplete,
              onError);

Of course you pass the username and password.  IsPersistent is a bool value indicating whether or not the user wants to be “remembered” by the application.  CustomInfo can be null as can the redirectUrl.  Of course, if you would like the user to be redirected to a certain Url after a successful log in, you’d specify that Url. The last two values are pointers to the methods to call when the login has completed or has errored out.  If you’re calling this from a web page it’s straight forward and from Silverlight, you’d need to wrap this code in a JavaScript function, and then call it from Silverlight like this.

Exposing Authentication as Web Service

Brad Abrams has an excellent tutorial on how to expose the needed functionality as a web service, here.  This was the approach I ended up using in my Silverlight application because it fit well with how the rest of the application was designed.   Once the functionality has been exposed as a web service, you could call this web service the same way you’d call any other from an Ajax application.

Tags:

.Net | Silverlight | WCF | ASP.Net

WCF Exceptions in Silverlight

by mgordon 6. May 2009 08:49

I’ve been working on a fairly substantial Silverlight 2 application and finally took on an aspect of it that I had been dreading and putting off for some time – exception handling – specifically handling exceptions being thrown from my WCF services.  I just knew this was going to be a bear.  Turns out, it wasn’t quite as bad as I had feared, but it was enough trouble that I thought a blog post sharing the experience would be a good thing.

The Problem

Silverlight doesn’t communicate directly with your web services, but rather it uses the browser API for this communication.  When calling a web service, if any exception occurs, the browser converts this into a generic 400 (Page not found) error and hands it back to Silverlight.  The result is that inside your Silverlight application, you know that an exception has occurred during your call, but have no way of knowing what it was.  This problem is supposed to be fixed in version 3.

The Research

This was certainly something I didn’t want to rush into solving so I did a bit of research on the Internet before jumping in.  Some we solving this by using out parameters on their services that contained the exception information which required checking the value of this parameter after each call.  I found a solution that was quite nice on CodeProject that used attributes on the service methods and contracts and a base class for the proxy on the client.  Since I’m still using Visual Studio generated proxies in my project, this one aspect of the solution made it unusable for my purposes.  In a discussion, here, I discovered that Microsoft’s Silverlight web service team had published a solution to the problem.  I checked it out and decided on this solution for my application.  A blog post about the solution can be found here and the code can be downloaded from code.msdn.microsoft.com.

The Code and Configuration

I found a few blog posts from folks who had implemented this solution, but none that were comprehensive and none that addressed its use with Visual Studio generated proxies.  Below, then, are the steps I took to get it all working in my application.

First, download the code the Silverlight web service team makes available and compile all the solutions.  You’ll need to set references to a few of the generated assemblies.

References

In the web project containing your WCF web services, set a reference to the assembly “SilverlightFaultBehavior.dll”.  Now, in your Silverlight project set references to the assemblies “SilverlightRawFaults.dll” and “SilverlightMessageInspector.dll”.

Code

If the web project containing your WCF web services doesn’t have a Global.asax file, add it and add the following code to it.  This code will cause any service requests that fail to return a 200 status code instead of 400.

 

protected void Application_EndRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.PhysicalPath.EndsWith(".svc", StringComparison.OrdinalIgnoreCase) &&
        HttpContext.Current.Response.StatusCode == 500 &&
        !HttpContext.Current.Request.Browser.Crawler &&
        HttpContext.Current.Request.Browser.EcmaScriptVersion.Major > 0)
    {
        // Set 200 if its a faulted service request
        HttpContext.Current.Response.StatusCode = 200;
    }
}
 

In any Silverlight class that makes a call to a WCF service, add the following (C#).

using Microsoft.Silverlight.Samples;
using SilverlightRawFaults;

At the point where you’re making the WCF call, you’ll be creating an instance of the proxy for that service.  Before making the call on that proxy, replace its binding by adding a line similar to this.

proxy.Endpoint.Binding = new BasicHttpMessageInspectorBinding(new SilverlightFaultMessageInspector());

This binding will ensure that the message inspector has a chance to look at the message returned from your call.

Finally, in the completed event for your service call, you’ll need to evaluate the Error property on the passed in event argument. 

if (e.Error != null && e.Error is RawFaultException)
{
    RawFaultException exception = (RawFaultException)e.Error;
    MessageBox.Show("Service says: " + exception.FaultMessage + Environment.NewLine +
        "Exception type: " + exception.FaultType + Environment.NewLine +
        "Stack trace: " + exception.StackTrace);
}
The Bug

After making the above modifications to my code, the value of the FaultMessage was not what I was expecting.  No matter what the exception was, this property always had the same generic value.  I found that there was a bug in the code provided by the Silverlight web service team and once it was corrected, all worked as expected.

Correcting the Bug

To correct the bug, open the downloaded solution called “SilverlightRawFaults”.  In the SilverlightRawFaults project, you’ll find a class called “BasicHttpMessageInspectorBinding”.  There is a property on this class called “FaultMessage” (oddly enough, the value that was incorrect).  Change this

public string FaultMessage 
{
    get { return Message; } 
}

to this

public string FaultMessage 
{
    get { return message; } 
}

Note that all I changed was the case of the “M” in “message”.  In this class, message is a member variable where Message is a property of the base class which is never set.  In the method RawFaultException sets message to the string containing the exception’s message, which is the value that should be returned.

Tags:

.Net | Silverlight | WCF

VisualTreeHelper Class in Silverlight

by mgordon 20. February 2009 08:37

It’s hard for me to believe I’d never encountered the situation before, but I was recently working on a part of a Silverlight application where I’d used a ListBox and specified an ItemTemplate within it containing a CheckBox and a TextBlock.  When a particular event fired, I wanted to iterate through all the ListBox Items, examine the Text property of the TextBlock and based on some simple logic, either check or uncheck the CheckBox.  My XAML for the ListBox looked like this:

<ListBox Margin="-5.057,34.225,0.116,0.121" Grid.Row="1" x:Name="lbRoles">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal" >
                <CheckBox Checked="CheckBox_Checked"></CheckBox>
                <TextBlock Margin="5,0,0,0" Text="{Binding Path=RoleName}" FontWeight="Bold" 
Width="Auto" HorizontalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight" LineHeight="15"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

So, basically, I was binding the ListBox to a collection and populating the TextBlock’s Text property from the binding.  My first task was to figure out how to access the ListBoxItem’s since The ListBox’s Items property would return the collection it was bound to and not the generated Items. I did some research and came across a newsgroup thread, here that contains an example of using the VisualTreeHelper class

In that thread, there is method defined like so:

private void GetChildren(UIElement parent, Type targetType, ref List<UIElement> children)
{
    int count = VisualTreeHelper.GetChildrenCount(parent);
    if (count > 0)
    {
        for (int i = 0; i < count; i++)
        {
            UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
            if (child.GetType() == targetType)
            {
                children.Add(child);
            }
            GetChildren(child, targetType, ref children);
        }
    }
}


You’ll notice that the method requires you to specify a type of control you’re interested in and also that it uses recursion to walk through every control in the visual tree beneath the specified parent.  I quickly found there is a vast hierarchy of controls created for the ListBox beyond what you’ll see in your XAML so it makes sense to recurse the tree of controls and only return what you’re needing.  I added this method to my class and used it for the above described problem like this:

List<UIElement> items = new List<UIElement>();
GetChildren(lbRoles, typeof(ListBoxItem), ref items);

foreach (ListBoxItem item in items)
{
    List<UIElement> children = new List<UIElement>();
    GetChildren(item, typeof(CheckBox), ref children);
    CheckBox cb = (CheckBox)children[0];

    children.Clear();
    GetChildren(item, typeof(TextBlock), ref children);
    TextBlock block = (TextBlock)children[0];

    if (_currentUserRoles.Contains(block.Text))
    {
        cb.IsChecked = true;
    }
    else
    {
        cb.IsChecked = false;
    }
}

So, using VisualTreeHelper and the helper method, I’m able to iterate through all the ListBoxItems and within each, to get a reference to the CheckBox and TextBlock within it.

Tags:

Silverlight | .Net

Using The ASP.Net Membership, Role And Profile Providers

by mgordon 17. February 2009 06:25

I’ve used these providers quite a bit over the past few years with good success.  As a simple overview, the Membership provider offers functionality that allows you to authenticate users against a store of users, the Role provider lets you authorize users to perform actions on your site based on roles they have been assigned and the Profile provider allows the saving of additional user details.  By using these providers, you can relieve yourself of having to roll your own functionality for these purposes.  I have found the Scott Mitchell’s tutorial located here to be an invaluable resource, but I have also picked up some tricks along the way.  Below, I’ll explain in a brief way how to set these providers up to use SQL Server as the data store. 

aspnet_regsql

First of all, we’ll need a place to store our information.  A utility is provided with the 2.0 version of the framework called aspnet_regsql.exe that will create all the required database objects for you.  The first decision you need to make is whether this information will live in your application’s database or in a separate database.  If your intention is to use the same user base across several applications, I’d elect to create a separate database for this information, otherwise I’d place the objects along side my application data.

Run the utility and you’ll be presented with the following screen.

regsql_screen1

Click Next> to continue the wizard.

regsql_screen2

Select the top radio button since we’re adding the database objects, not removing them.  Click Next>.

regsql_screen3

Select the SQL Server to install the objects to, credentials to authenticate (NOTE: The credentials used must have rights to create tables, views, stored procedures, etc on the specified database) and database.  If the database already exists, the objects will be created in it.  If the database specified does NOT exist, it will be created and then the objects will be created in it.  Click Next>.

regsql_screen4

This screen gives you an opportunity to review your choices.  If the information is correct, click Next>, otherwise click <Previous and correct your choices.  Clicking Next, here, creates the objects in the specified database.  Objects for all providers are created in the database.  You select the ones you wish to incorporate into your application by specifying them in the web.config file.  Let’s look at how to set up the providers.

Setting Up The Providers

The first thing we’ll need to do, is tell the providers where to find their data.  We do this by specifying a connection string in web.config.

<connectionStrings>
    <add name="Connection" connectionString="Data Source=ProviderDatabase; 
initial catalog=ProviderDB;
uid=user; password=pass"/> </connectionStrings>

All the providers we specify in web.config will reference this connection string section.

Now, we need to start configuring our providers.  We so this in the <system.web> section of the web.config file.

<roleManager enabled="true">
  <providers>
    <remove name="AspNetSqlRoleProvider"/>
    <add connectionStringName="Connection" applicationName="/MyWebApp" 
name="AspNetSqlRoleProvider"
type="System.Web.Security.SqlRoleProvider,
System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"/> <remove name="AspNetWindowsTokenRoleProvider"/> <add applicationName="/MyWebApp" name="AspNetWindowsTokenRoleProvider"
type="System.Web.Security.WindowsTokenRoleProvider,
System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"/> </providers> </roleManager> <profile> <providers> <remove name="AspNetSqlProfileProvider"/> <add name="AspNetSqlProfileProvider" connectionStringName="Connection"
applicationName="/MyWebApp"
type="System.Web.Profile.SqlProfileProvider, System.Web,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
"/> </providers> </profile> <membership defaultProvider="CustomizedProvider"> <providers> <clear/> <add name="CustomizedProvider" type="System.Web.Security.SqlMembershipProvider"
connectionStringName="Connection" applicationName="/MyWebApp"
minRequiredPasswordLength="5" minRequiredNonalphanumericCharacters="0"
enablePasswordRetrieval="false" enablePasswordReset="true"
requiresUniqueEmail="true" maxInvalidPasswordAttempts="4"
passwordAttemptWindow="10" requiresQuestionAndAnswer="false"/> </providers> </membership> <authentication mode="Forms"> <forms loginUrl="Login.aspx"/> </authentication> <authorization> <deny users="?"/> </authorization>

In the above, I’m specifying that I want to use the Role, Profile and Membership providers.  Notice the use of <remove> and <clear> tags.  The way the config files work is that they start at the machine level (machine.config) and get settings from there.  Then the web.config for the root web site is combined with that and so on down the hierarchy until the level at which your application sits.  There is a chance that a conflicting configuration will exist at some level above your site that will prevent the providers from working properly.  The <remove> and <clear> tags remove any existing settings so our providers remain as the only ones defined.

Next, notice how the each of the providers requires an attribute, connectionstringname.  This should always be the name of the connection string section that points to the database where your provider objects were created.  In our case, above, we created a connection string section named “Connection”, so that’s the section we specify to each of the providers.  Each provider also requires an attribute of applicationName.  Two things to remember, here.  First, this needs to be the actual name of your site and the second is to always preface this name with a forward slash if the application is sitting somewhere below the root of the site.  Since it’s possible for you to use the same provider database for multiple sites, the site name is used by the providers to determine which set of settings apply.  If you forget the forward slash for a site below the root, you’ll find that you get duplicate application records in your database…one with and one without a slash for the application name.

The Membership provider allows quite a lot of configuration.  The example, above, specifies many of the allowable settings but not all.  I highly recommend you look at the documentation to see all that can be specified.

Since we are going to use the Membership provider to log our users into the site, we need to set up forms authentication.  This is being done in the authentication and authorization tags.  Here, we’re saying we’re not allowing anyone to access the site unless they have logged in and if they have not yet logged in, we redirect them to the Login.aspx page.  On this page, you can simply drag on the login control from the toolbox.  No further setup is required.  The control is smart enough to get all it needs from the web.config file.  When the user logs in, the Membership provider will automatically be used and the user will be authenticated against the database.

Since we specified the Login.aspx page as the login page, users automatically get access to it without having to be logged in.  What if we wanted to use some of the other controls provided with ASP.Net to manage our account like password recovery or changing passwords?  We can do this by creating the pages for the purpose at hand and dragging the appropriate control onto it.  All controls of this type will know how to use the provider automatically.  However, if a user should be able to access the page without having logged in, first (password recovery, for example), we’ll need to allow for this.

As we have configured the site, users can only access Login.aspx without having logged in and all other content is inaccessible to non-authenticated users.  We need to make an exception of the pages in question so the rules don’t apply to them.  To do this, we create a <location/> section in web.config. Just below the <system.web/> section, add the following.

<location path="RecoverPassword.aspx">
  <system.web>
    <authorization>
      <allow users="*"/>
    </authorization>
  </system.web>
</location>

This section, in effect, says, “For this one page, allow all users".”

Tags:

.Net | Productivity | Sql Server 2005

ActiveX Killbits Problem with Reporting Services Printing

by mgordon 13. February 2009 08:01

We just found and corrected a problem with printing from the reporting services web interface.  When the user clicked the print button, they received a popup message saying ""Unable to load client print control”.  As we found out, the problem was created when the users’ desktops installed a hotfix from Microsoft, KB956391.  We had two choices upon finding this out; we could remove the patch from every workstation or install a subsequent hotfix to Sql Server.  We opted for the latter and installed the hotfix located here.  Printing seems to work perfectly, now.

Tags:

Database | Sql Server 2005

Silverlight, WCF and Domain Names

by mgordon 14. January 2009 11:33

As I learn more about WCF, especially as it’s consumed by Silverlight, the better equipped I am to identify and solve problems.  This is what I keep telling myself as a justification for the time I spend and angst I feel sometimes as I feel my way through my first significant Silverlight application.

I am far enough along that I wanted to add a deployment step to by build process which would copy all the requisite application files to a web server I have running at home.  My main goal was to iteratively deploy the application, as it progressed, so some folks whose opinions matter to me could look at and play with the application and give me feedback.

When I created the Visual Studio solution for my application, I elected to have VS create a web application for me and my .xap file and WCF services are both hosted in that application.  So, as I develop, I’m typically working in a mode where I’m running the web application in the development web server so I can make service changes on the fly.  This all worked fine in regard to being able to communicate with my services from the Silverlight application.

I realized, after deploying, that my Silverlight application would need to talk to services running on my server instead of locahost, so before checking in the code each time, I changed my service references to point to services located there.  More specifically, to point to a domain I have set up for that server.  I checked in, the build deployed the application, I tested and found no joy at all.  As I investigated, I discovered that when I set my service references to point to my domain (http://www.domain.com/MyService.svc) what was actually being recorded in web.config and the artifacts that were created by adding the reference was http://machineName/MyService.svc.  After a good bit of research and thinking about the problem, I found the solution.

The root of the problem has nothing to do with Silverlight or WCF.  It’s actually a web site configuration issue that can be corrected by going to the Internet Information Services MMC Snap-In, and drilling down to your web site.  Note that if IIS is listening on only one port, this will be the “Default Web Site”.  In IIS 6 and before, you’ll want to go to the “Web Site” tab and click the “Advanced” button.  You should see a window like the one below.

WebSiteConfig 

Notice that this site is listening on port 80 and has no Host Header Name and so the default value is used which is the name of the machine IIS is running on.  To correct the problem, select the one row and click the edit button.  Then, fill in the Host Header Name such that it matches your domain like www.domain.com and click OK.

For IIS 7, select the web site in the tree view, select the “IPv4 Address and Domain” icon and then click the “Bindings” link on the right hand side.  Select the record for port 80 and click the Edit button.

websettings

Enter your host name, as above, and click the OK button and then the Close button.

After making this change, your service references should be scoped to your domain instead of to the machine name.

Tags:

.Net | Silverlight | WCF

Silverlight and WCF Serialization Woes

by mgordon 29. December 2008 04:58

So, it's been a good while since my last post.  It's been a crazy several months and time has been scarce to devote to blogging, but my situation has changed and I'm back in the saddle.

After spending the past couple of years working on .Net 2.0 project, I've spent the last few months playing catchup on some of the latest fodder to roll out of Microsoft...Linq, Silverlight and WCF.  I have a long way to go on each, but with time and a bit of effort I should be caught up in good time.  As is my usual style, I'll be posting about the stumbling blocks I encounter and how I managed to either solve or mitigate them.  This first post concerns a problem I faced working with WCF services from a Silverlight project.  Here are the details.

Being a newbie to Silverlight, I cruised over to Microsoft's Silverlight web site, watched the videos and read the tutorials before getting started.  I felt I had a pretty good grasp on things and started work on an idea I had.  I created a Silverlight project and allowed Visual Studio to create a web project for me, as well.  I, then, added a third project to host my service layer which would be made up of Linq to Sql calls, so I also created the dbml file, there, that represented my database.  The idea was that the Silverlight project would call WCF services hosted in the web project which would in turn call methods in the Service layer to query and effect changes in the database.

I started work and created several methods on my WCF service.  Each time I added functionality to the service, I would right-click the service reference and select "Update Service Reference" to allow the new methods to be generated in my proxy (I'm aware that using Visual Studio to generate WCF client code is emerging as an anti-pattern.  I will, at some point, replace the generated code with code of my own creation...stay tuned for more on this).  After several days with no problems, I repeated this process again and had several warnings raised saying that no proxy could be generated and that my service was not Silverlight compatible.  Hmmmm.

I rechecked all the classes I was sending over the wire to make sure the right serialization attributes were present.  I ran svcutil.exe against my service and it generated a proxy, just fine.  As a last ditch effort, I recreated the web project tried again only to have the problem reoccur.  I was truly stumped.  So, I reverted my service reference code to a good state and continued to look around and found nothing until I had a revelation.  When you right click the service reference, there is an option to "Configure Service Reference".  This opens a dialog that allows you to tweak the settings for the service that control what generic classes among other things.

servicerefconfig

In the lower part of the box, you are allowed to chose which types to reuse.  Best I can tell, this reuse involves serialization since the types would be "reused" on both sides of the service binding.  Upon inspection, I found that some Telerik assemblies were included in the list.  If I chose the lower radio button and unselected the Telerik assemblies, my service reference was generated properly.  Apparently, some of the types in one or more of these assemblies could not be serialized.

This is an example of the kind of thing that can happen and the frustration it can cause when you know just enough about a technology to be dangerous.  I'll be working hard to remedy this in the coming days.

Tags: , , ,

.Net | Linq | Silverlight | WCF

Versioning WF Flows

by mgordon 17. June 2008 07:58

I posted, previously, about my foray into Windows Workflow.  In that post, I described a bit about the application I was writing and how I was using Workflow to solve the problem of moving orders through various business processes.

Well, the application is maturing and I recently deployed an update to the original flow definitions and everything ground to a halt.  I was aware of the versioning issues, thought I had it covered, but I didn't.  Before I delve into the details, I want to say that while I find the current story around versions of flows to be lacking in many ways, I honestly can't think of a better solution to the problem.  That said, the approach reminds me a bit of the versioning of COM interfaces in the good old days.

The problem goes something like this...I deploy a version of my flow (say version 1) and I start sending items down the flow.  These are long running processes, so I'm using the persistence service and database to store the state of my flow instances as needed.  At any point in time, I have several instances at various states of completion with state stored in the database.  I decide I need to change one of my flows and replace version 1 with version 2, of my code.  Now, all the instances that were in my persistence database that were expecting to run on version 1 of my flow are stuck.  There is a strong affinity between a persisted instance and the version of code it was started on because the version of the code is part of the persisted state.  Also, the state of each activity in the flow is persisted.  If I've added, removed or rearranged any of my activities, the state will no longer fit into the flow when it's dehydrated.  If an attempt is made to continue the a flow from version 1 on the version 2 code base, the result is an odd index out of bounds exception.

I did a lot of searching to find a solution to this problem and no where did I find the complete solution.  After piecing it all together and doing some experimentation, I finally hit on the secret sauce.  The only mention of this problem, that I could find on MSDN was here and mentions only that .Net versioning practices should be employed.  So, being the bright guy that I am, I proceeded to generate a key pair (using SN.EXE), marked my project containing the flows as being strong named and associated it with my key pair for signing.  The objective, here, is to be able to keep all versions of your flow around.  So, I GAC version 1 and also version 2.  The workflow engine is smart enough to discern which version the instance should be loaded back in to.  I understand this approach and it seemed to me it would work, but it didn't.

If you're using persistence and not using a timer, you must be firing events into your flow to get it to continue after it's been persisted.  To do this, you need to use the External Data Exchange service.  You define an interface that contains the events that can be fired into the flow - and another for events the flow can fire out to your host.  You then create classes that implement the two interfaces ad register them for use.  In my implementation, I had events going both ways.  After deploying both versions of my flows, I tried to fire an event to an existing instance.  This produced an exception stating that the event could not be delivered because the queue had not yet been created.  WHAT???

The problem here was how I had my classes grouped into projects.  I had my flows and External Data Exchange interfaces defined in the same project which meant that I could not version my flows apart from the interface.  While I have not found documentation to back it up, my suspicion is that regardless of what versioning tactic you use, a new version of the interfaces will not be tolerated.  The only solution to this is to move the interfaces and the code that implements them into a separate project and never touch the version number for it.  After rearranging my classes and projects, I was able to start instances, allow them to persist, deploy an addition version of my flows and continue the previous instances.

The bottom line for me was that I had to make such deep changes to my workflow code, that some of the existing instances had to be thrown away as unusable.  The moral, here, is to make sure you have a correct versioning strategy in place from the get-go or risk losing data later on.

Before closing I wanted to mention that I did see mention of folks being able to actually hack the persistence database records to recover from this situation.  This is not for the faint of heart and was definitely not for me.  You can find some instruction, out there, on how to do this but do it at your own risk.

Tags:

Workflow

On Building Deployments From Source Control

by mgordon 29. April 2008 08:13

Recently, I needed to make some changes to an older application that was created before I joined the team.  I set out to find the most recent version of the source for this application.  The team, at the time the application was built, used a combination of Visual Source Safe and backing up copies of the source (not the source database) to both a share on the network and also an external hard drive that was hanging off one of the developers' workstations.  I first checked the backups on the hard drive and found 20 copies of the source there.  Apparently, most all the copies had been moved at the same time because the time stamps on the files were identical.  Some of the folders had dates in the names, but had sub-folders with multiple versions in them.  In checking the share, I found basically the same thing.  Next, I checked VSS and found the source checked out by an employee no longer with the company and that about 5 months of bug fixes had been made without checking the code back in.

So, after the shiver went down my spine, I went about trying to decide how I was going to handle the fact that I had a version running in production that was about 5 months newer than the latest version of source code I could find.  Not a pretty situation...

This experience just underscores the value of having and using an automated build system and a process that keeps it a central part of the overall approach to things.  With a build server in place, the release versions are generated FROM source control.  So, unless you lose your repository, it's impossible to deploy a version that isn't in the source database.

I found another problem with the source, as well.  It depended on several third party controls.  Apparently, the controls had been installed on the developer's computer and references from the project to the third party assemblies had been made to the installed location.  What this meant for me was that after I had obtained the source code, I had to go hunting for the assemblies (there were multiple versions involved) in order to get the references corrected so  the project would even compile.  This makes getting set up to modify an existing application a long and arduous task.  Then, too, the controls have to be installed on your build server in exactly the same location as on the development box or your builds will fail, as well.

Instead of doing it that way, try creating a folder, in your project, that contains all the third part assemblies required by the application.  If you like, you can even subdivide them by vendor, purpose, or whatever in sub folders beneath.  Then, set all your references to the assemblies in those folders.  Make sure, too, that these assemblies get checked into source control along with your source code.

Now, when a new developer goes to check out the code to work on it, all the dependencies are there, working, and a clean compile is only a click away.  Same goes for the build server.  You won't have to worry about installing the dependencies there, at all.

Tags:

.Net | Productivity

Hosted Services

by mgordon 23. April 2008 07:25

Some time ago, I was looking for a way to set up a family calendar so we could all keep track of one another's plans and schedules.  Being a typical, time challenged family of the new century we were having a hard time keeping track of all our activities.  My first thought was to try to whip something up from scratch, but being the spare-time-challenged individual that I am made that a difficult proposition.

Around that time, I had listened to Scott Hanselman's HanselMinutes episode about Google Apps and Windows Live Custom Domains.  I immediately went to find out all the details.  The idea with both of these services is that you obtain a domain name and then configure that domain to be redirected to one of these companies' properties for services like email, productivity applications, calendaring, blogging, etc.  You can check out Microsoft's offerings  and Google's .  I elected to sign up for Google Apps.  I found the signup and setup process extremely simple though it does require that you have access to change and knowledge about the DNS entries for your domain.  The instructions on the web site are easily followed, though.  Initially, the URL's to the various features are quite cryptic, but Google provides a way for you to replace these paths with sub-domains, if you choose.  For example, the path to my domain's GMail login was something like https://www.google.com/a/codespot.com/ServiceLogin?service=mail&passive=true&rm=false&continue=http%3A%2F%2Fmail.google.com%2Fa%2Fcodespot.com%2F&ltmpl=default&ltmplcache=2 and by taking advantage of a sub-domain, it became mail.codespot.com.

The services allow you to set up an eco-system for any group of folks that you like.  You create accounts for those you wish to have access to your domain's offerings and the content you keep there can either be exclusive to the members of the group or shared with all netizens. 

All my family members now have a personal calendar and any of us can choose to overlay our calendar with the events schedules on the calendar of another family member.  We can choose to be notified via email or SMS of any event we choose.

With both offerings, the best feature is that it's all for free.

Tags:

General | Productivity

Powered by BlogEngine.NET 1.5.0.7
Theme by Extensive SEO