How to create a custom Value Provider for MVC

Problem: I need to test an MVC Controller Action that needs the Identity of the current user without mocking the HTTPContext. Solution: Create a custom Value Provider that allows access to the current user via an Action Parameter. Explanation: One of the goals of the MVC pattern is making the application easier to test.  Simply using the pattern does not grantee your application will be easy to test.  The application must be designed with testing in mind.  This does not require that you use Test Driven Development (TDD) but I do believe you must be what I like to call "Test Aware".  You must constantly be thinking during your design how are we going to test this? Does this design lend itself to easy testing?  Testing can no longer be an afterthought. While recently working on a MVC project I ran into an issue that was going to be very difficult to test because it relied on the read only User property of the Controller base class.  My goal was to find a way to allow my action to be tested without having to Mock the HTTPContext.  The action I was testing required Authorization and used the User.Identity property to query information from the data store.  Because the User property of the Controller base class is ready only I was unable to set it in my unit test which would require me to mock the HTTPContext to test that action. MVC Controllers have several mechanisms for receiving data.  You can access the data from context objects, invoke the framework's model binding feature or have the data passed as parameters using a value provider.  I prefer my action methods to have data passed as parameters.  When your action depends only on the parameters, without accessing context data directly they become much easier to understand and test.  Actions that only depend on their parameter are called "Pure". When your action method accepts parameters the framework employs the help of a collection of Value Providers and Model Binders to locate suitable values.  Like many components in the MVC framework Value Providers and Model Binders are pluggable.  This flexibility in the MVC framework allows developers to replace or extend the framework.  My solution was to simply create a custom Value Provider that would allow me to access the current user as an input parameter to my action method. Below is an example of the way the action would be written if you access the User property of the Controller base class.[Authorize]public ActionResult Index(){   Models.Userdetails clerk = context.Userdetails.Where(u => u.Username == User.Identity.Name).Single();   return View(context.Citations.Where(c => c.ID == clerk.ID &&                                             string.IsNullOrEmpty(c.UploadedBy)));}However, to test this method would be very difficult.  Instead I decided to write my action method so that it accepts a GenericPrincipal object as a parameter.[Authorize]public ActionResult Index(GenericPrincipal currentUser){   Models.Userdetails clerk = context.Userdetails.Where(u => u.Username == currentUser.Identity.Name).Single();   return View(context.Citations.Where(c => c.ID == clerk.ID &&                                             string.IsNullOrEmpty(c.UploadedBy)));}By writing the method this way I was able to create my test method without having to mock anything.[TestMethod]public void Index(){   // Arrange   HomeController controller = new HomeController();   // Act   GenericIdentity id = new GenericIdentity("userName");   GenericPrincipal user = new GenericPrincipal(id, null);   ViewResult result = controller.Index(user) as ViewResult;   // Assert   ViewDataDictionary viewData = result.ViewData;   Assert.IsTrue(viewData.Model is IEnumerable<Models.Citations>);}To achieve this design I had to extend the Value Providers with a custom class.Writing a custom Value Provider is very simple.  You simply create a class that implements the IValueProvider interface.  The IValueProvider interface only has two methods:•    ContainsPrefix - This is your value providers way of letting the MVC framework know you can handle this item.•    GetValue - If you return true from ContainsPrefix this method will be called to provide the value.To allow the MVC framework to access your value provider you must provide a ValueProviderFactory class as well.  This class derives from ValueProviderFactory and simply returns an instance of your Value Provider. The code below shows both the Value Provider Factory and the Value Provider.public class CurrentUserValueProviderFactory : ValueProviderFactory{   public override IValueProvider GetValueProvider(ControllerContext controllerContext)   {      return new CurrentUserValueProvider();   }   private class CurrentUserValueProvider : IValueProvider   {      public bool ContainsPrefix(string prefix)      {         return "user".Equals(prefix, StringComparison.OrdinalIgnoreCase);      }      public ValueProviderResult GetValue(string key)      {         return ContainsPrefix(key)            ? new ValueProviderResult(HttpContext.Current.User, null, CultureInfo.CurrentCulture)            : null;      }   }}The final step is to register your Value Provider Factory with the MVC framework.  Add the highlighted code to the Application_Start method inside Global.asax.cs protected void Application_Start(){   AreaRegistration.RegisterAllAreas();   RegisterRoutes(RouteTable.Routes);   ValueProviderFactories.Factories.Add(new Classes.CurrentUserValueProviderFactory());}This adds your custom Value Provider to the MVC framework and allows you to gain access to the current user in any action method by simply having a GenericPrincipal user parameter.

Why is my MS Project run so slow when connected to TFS.

Problem: With MS Project connected to TFS Project takes forever to refresh. Solution: One possible solution is to change the calculation mode from automatic to manual.  To change the calculation mode select Tools / Options / Calculation / Calculation Mode and change from automatic to manual.

Having trouble testing my WPF app with Coded UI Test

Problem: I cannot find my WPF TextBlock using the Coded UI test because the value is data bound and changes. Solution: Set the Name attribute on the controls of your View which sets the AutomationId. Explanation: Many WPF developers only place the Name attribute on items they intend to access from a code behind.  With most WPF developers using MVVM and trying to keep their Views as light as possible there would be no need to use the Name attribute.  However, if you intend to use Microsoft's new Coded UI test to test your view the Name attribute is important. The Coded UI test uses the Accessibility Framework to locate the controls on the screen.  The more distinct attributes the item has the more likely the test will be able to locate that control during playback. The Name attribute on WPF controls sets the AutomationId and allows it to be used to locate the control.  This is important when the value of for example a TextBlock changes.  If the Name attribute is not set the actual content of the TextBlock which is going to be changing during execution will make it almost impossible to locate that control during playback

I can't generate MySQL DDL from my Entity Framework edmx file.

Normal 0 false false false EN-US X-NONE X-NONE /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin-top:0in; mso-para-margin-right:0in; mso-para-margin-bottom:10.0pt; mso-para-margin-left:0in; line-height:115%; mso-pagination:widow-orphan; font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} Problem: I have installed the MySql .NET Connector but when I try to generate a database from my Entity Framework model it only generates DDL for SQL Server. Solution: You must change the DDL Generation Template for the Model.  Open your edmx file and right click on the design surface and select Model Browser from the context menu.  Now in the Model Browser right click on the model and select Properties.  In the Properties window change the DDL Generation Template from (VS) to (VS).

I need to show TFS history of a file on the command line so I can redirect to a text file.

Problem: When I run the tf history command from the command line it shows a dialog box. Solution: Add the /noprompt option to the TF History command. This will cause the output to be shown in the command window. You can then use DOS redirection to easily store the results in a text file. For example: tf history $/MyProject/Main/Source /recursive /noprompt /format:detailed /collection:http://MyTFS:8080/tfs/defaultcollection > history.txt This will result in a new file called history.txt to be created in the working folder. Explanation: The key to not showing the dialog box is the /noprompt.  If you leave off the /noprompt you will be shown a dialog box. The output redirection operator > is used to send the command output to somewhere other than the screen for example a text file. > somefile.txt (If the file already exists it will be overwritten.)>> somefile.txt (This will append a file. If the file does not already exist it will be created.)

I have code I don't want used to calculate code coverage or code metrics

Problem: I have code that I don't want to be calculated in my code coverage results and/or my code metrics. Solution: Apply the GeneratedCodeAttribute, DebuggerNonUserCode or DebuggerHidden attributes to the specific code. Explanation:   GeneratedCodeAttribute DebuggerNonUserCode DebuggerHidden Code Metrics Excludes code No Effect Code Analysis Excludes code No Effect Code Coverage No Effect Excludes code

How to add a SharePoint portal after you created the Team Project

Problem: I created a team project and did not select the option to create a share point site and now I want to add one. Solution: Create a dummy site and remove the link to sharepoint and wire it up to the original team project. Or two create a new site in SharePoint and wire it up. Explantion: There is a great write up here on how to do both options.

How do I validate data in my database during a web test

Problem: The only way I can verify the success of my web test is to read a value from a database. Solution: Create a custom validation rule that can validate the value in the database. Code: using System; using System.ComponentModel; using System.Data.SqlClient; using Microsoft.VisualStudio.TestTools.WebTesting; namespace TestUtil {    [DisplayName("SQL Validation Rule")]    [Description("Executes the query and compares the first column of the first row to the Expected value.")]    public class SQLValidationRule : ValidationRule    {       public SQLValidationRule()       {          IgnoreCase = true;       }       [Description("The query to execute and extract the first column from. In Select * from x where column={0}. You can leave the where clause if it is not needed.")]       public string Query { get; set; }       [DisplayName("Connection String")]       [Description("The full connection string to the database")]       public string ConnectionString { get; set; }       [DisplayName("Where Clause Context Parameter Name")]       [Description("The name of an optional context parameter to use if there is a where clause in the query.")]       public string WhereClauseContextParameterName { get; set; }       [DefaultValue(true)]       [DisplayName("Ignore Case")]       [Description("When set to true the case of the word is not used")]       public bool IgnoreCase { get; set; }       [DisplayName("Expected Value")]       [Description("The value to compare the first column too.")]       public string ExpectedValue { get; set; }       public override void Validate(object sender, ValidationEventArgs e)       {          string where = null;          if(!string.IsNullOrEmpty(WhereClauseContextParameterName))             where = e.WebTest.Context[WhereClauseContextParameterName].ToString();          string result = ExecuteQuery(ConnectionString, Query, where);          e.IsValid = string.Compare(result, ExpectedValue, IgnoreCase) == 0;       }       private string ExecuteQuery(string connectionString, string query, string where)       {          SqlConnection conn = new SqlConnection(connectionString);          string cmdText = string.Format(query, where);          SqlCommand cmd = new SqlCommand(cmdText, conn);          try          {             conn.Open();             SqlDataReader dr = cmd.ExecuteReader();             if(dr.Read())                return dr.GetValue(0).ToString();          }          catch(Exception e)          {             System.Diagnostics.Debug.WriteLine(e.Message);          }          finally          {             conn.Close();          }          return null;       }    } } Explanation: Creating a custom validation rule for web test is extremely simple.  Simply create a new public class that derives from Microsoft.VisualStudio.TestTools.WebTesting.ValidationRule and override the Validate method.  If you create the class in your test project it will become immediately available the next time you try to add a validation rule to a web request.  If you created the class in a separate class library simply add a reference to that class library in your test project. This particular validation rule has the five following properties: Query – This is the query to be executed on the database connection.  Only the first column of the first record is used in the comparison of this validation rule.  The query can have a single where condition in the where clause that uses a context parameter value.  For example “Select Name from Table1 where ID={0}”.  At runtime the validation rule will look up the value of the provided context parameter and replace {0} with the value stored in the context parameter.  Using a context parameter is completely optional. Connection String – The connection string to a SQL Server database. This can also be a context parameter entered in {{ContextParameterName}} format.  Otherwise you may simple enter a literal string. Where Clause Context Parameter Name – The context parameter to be used to replace the {0} if any of the query. Ignore Case – Identifies if case should be ignored or not during the string comparison. Expected Value – The value to compare the first column of the first row too.  This can also be a context parameter entered in {{ContextParameterName}} format.  Otherwise you may simple enter a literal string. You can download the file below. SQLValidationRule.cs (2.48 kb)

How to change the display name of my Find Text validation rule

Problem I can’t easily tell what my Find Text validation rule is searching for in my Web Test. Solution Change the DisplayName value in the Web Test xml to something more meaningful. From Solution Explorer right click on the Web Test and select Open With… then select XML (Text) Editor and click OK.  Once the file is open search the file for DisplayName="Find Text".  Replace Find Text with something more meaningful.  Save the file and close it.  Now right click on the Web Test from Solution Explorer and select Open With… and select the Web Test Editor (Default).  Now expand the Validation Rules folder under the desired web request.  The Find Text validation rule label will be the value you typed in. Explanation For some reason the creator of this validation run did not expose the DisplayName property so it could be change from the Properties Window.  However, the value is there and can be changed from the xml file.  This is very helpful when you have several Find Text validation rules on the same request.

How to Xcopy deploy using TFS 2010/2012

Problem I need my VS2010/VS2012 build to perform an “Xcopy deployment” of my ASP.NET application to an existing virtual directory. Solution Customize the build template to use the CopyDirectory activity to copy the ASP.NET application to the virtual directory. Explanation One of the benefits of ASP.NET development is the simply “Xcopy deployment”. ASP.NET applications require no changes to the registry and have no special installation requirements for the hosting server.  Therefore, you can use the drag-and-drop feature in Microsoft Windows Explorer, File Transfer Protocol (FTP), or the DOS Xcopy command to copy files from one computer to another. The only prerequisite of this technique is the virtual directory in IIS must already be created and configured. The goal of this build is to not have to install any special features or extensions in IIS to facilitate deployment of my ASP.NET application.  I want my environments to match production as close as possible and I never intend on installing IIS Extensions in production. When you configure a build definition that builds and ASP.NET application the binaries directory and drop location contain a folder named _PublishedWebsites.  Each ASP.NET application built during the build will have a sub directory that contains all the files needed for the application. To perform an “Xcopy deployment” we simply need to identify the source and destination directories.  We are going to store this information in arguments passed to the build.  To begin open the DefaultTemplate.xaml file in VS2010 and click the Arguments button at the bottom of the workflow designer to show the workflow arguments.  Add two string arguments  VDir and SiteDir. Now let’s add a nice coat of polish on our arguments.  Click the ellipses next to the default value of the Metadata argument to show the Process Parameter Metadata Editor window.  Click the Add button and enter in the following information and click OK. Parameter Name – VDirDisplay Name – Virtual DirectoryCategory – DeployDescription – The full UNC path to the virtual directory to copy the website too. Editor – leave blankRequired – leave unchecked View this parameter when – Always show the parameter and Parameter Name – SiteDirDisplay Name – Site DirectoryCategory – DeployDescription – The sub directory of _PublishedWebsites to copy from.Editor – leave blankRequired – leave uncheckedView this parameter when – Always show the parameter   We are simply going to add a CopyDirectory activity that uses the arguments we just created to perform the copy.  To begin we must locate the correct area of the build template to add our CopyDirectory activity.  I find the quickest way to do this is to click the Collapse All button at the top of the workflow designer window.  Now double click on the words Double-click to view on all of the following activities: 1.    Run On Agent2.    Try Compile, Test, and Associate Changesets and Work Items 3.    Sequence4.    Compile, Test, and Associate Changesets and Work Items5.    Try Compile and Test6.    Compile and Test7.    For Each Configuration in BuildSettings.PlatformConfigurations8.    Compile and Test for Configuration When we configured the metadata for our arguments we left the Required checkbox unchecked.  This will allow users of this build template to leave the values for VDir and SiteDir blank if they are not building an ASP.NET application or simply do not want to deploy them.  Therefore, we need to check the value of the arguments to determine if we need to perform the copy or not.  In the toolbox expand the Control Flow tab and drag and drop the If activity right above the If Not Disable Test activity.  Click the double down arrows in the title bar of the if to show its contents. In the Condition text box enter the following: Not String.IsNullOrWhiteSpace(VDir) From the toolbox drag and drop a Sequence activity from the Control Flow tab onto the Then side of the If.  Change the DisplayName of the sequence to Deploy ASP.NET Application. We add a sequence here so that we can use multiple activities. Click the double down arrows in the title bar of the sequence to show its contents.  This is where we are going to add the activities needed to copy the ASP.NET application to the virtual directory in IIS. Now we can add the CopyDirectory activity and set the properties to deploy our ASP.NET application during the build.  To get started simply drag and drop the CopyDirectory activity from the Team Foundation Build Activities tab into the Deploy ASP.NET Application sequence.  With the CopyDirectory activity selected set the following values in the properties window: •    Destination – Vdir•    Source  - BinariesDirectory + "\_PublishedWebsites\" + SiteDir Now save your xaml file, check in your changes and queue a new build. You can download a copy of the final file below. TFS2010 DeployTemplate.xaml (55.16 kb) TFS2012 DeployTemplate.11.1.xaml (75.68 kb)