Archive for the ‘ASP.NET’ Category
ASP.NET WebApplication Fails To Load In Visual Studio 2008 After Upgrading In Visual Studio 2010
Today after upgrading a ASP.NET Web Application project in Visual Studio 2010 the project failed to load in Visual Studio 2008. If the machine has both VS2008 and VS2010 installed then the project loaded just fine. But, if a machine does not has VS2010 installed the Web Application failed to load.
After the upgrade Visual Studio 2010 modified the following:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" /> TO <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
Because the v10.0 (second) path is not present in machines that do not have V2010 installed, VS2008 was unable to load the project.
After googling I came across this post which tells to use MSBuild’s condition statements to specify the correct path based on the the Visual Studio version. His solution worked fine, the only problem that I faced was when I open the solution in VS2010, it again asked to upgrade the project file, doing which changed the v9.0 path to v10.0 path.
I had to make few minor changes to solve this problem:
Step1:
Add the V10.0 path before the V9.0 MSBuild extension path with a Condition property to check for the file based on the Solution Version.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="'$(Solutions.VSVersion)' == '10.0'" /> <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" Condition="'$(Solutions.VSVersion)' == '9.0'" />
Here is we do not specify the Visual Studio 2010 MSBuild extension path first the Visual Studio will try to upgrade the project.
Step2:
After the project file upgrade VS2010 would have changed the FileUpgradeFlags tags value to 0, which would again trigger an upgrade. Remove the Zero from the tag.
<FileUpgradeFlags></FileUpgradeFlags>
Save the project file and reload. Now you will be able to load the project in VS2010 & VS2008 (Even if VS2010 is not installed) without any problem.
Hope it helps.
Windows 2008 & Visual Studio Web Setup: The installer was interrupted before ApplicationName could be installed
Although how much I hate creating setup packages, I had to create a few setups for some of my projects recently. While I was working on setup projects, I found that, the capabilities of Visual Studio Setup & Deployment projects are shockingly limited, and not to mention I faced a lot of issues while creating setup projects in Visual Studio. Few people suggested me to use WiX. WiX certainly is good and far more flexible solution for building Windows Installer Setup Packages, but it has got a very steep learning curve.
I will be making few posts in future about the problems, that I faced during my experience creating setup packages using Visual Studio. So, here you go. Here is the first problem.
The Problem
I was working on a simple Web Setup project in Visual Studio 2008. The setup worked fine in XP & Windows 2003 server. But, when I tried installing the setup in Windows Server 2008, I got this nice error message that said. “The installer was interrupted before <MyApplicationName> could be installed. You need to restart the installer to try again.”
Having faced many problems earlier with msi packages, I at least knew how to start the msi package in verbose mode to create the log files.
Launch your msi in verbose mode:
msiexec /i yoursetup.msi /lv "C:\yourdirectory\logfile.txt"
I searched for terms like “ERROR” & “FATAL” in the log file
. I got this.
Action ended 15:57:43: WEBCA_MYSETUPTARGETVDIR. Return value 1. MSI (c) (8C:20) [15:57:43:204]: Doing action: WEBCA_SetTARGETSITE Action start 15:57:43: WEBCA_SetTARGETSITE. MSI (c) (8C:20) [15:57:43:206]: Note: 1: 2235 2: 3: ExtendedType 4: SELECT `Action`,`Type`,`Source`,`Target`, NULL, `ExtendedType` FROM `CustomAction` WHERE `Action` = 'WEBCA_SetTARGETSITE' MSI (c) (8C:A0) [15:57:43:226]: Invoking remote custom action. DLL: C:\Users\ADMINI~1\AppData\Local\Temp\1\MSI4225.tmp, Entrypoint: SetTARGETSITE INFO : [03/31/2010 15:57:43:286] [SetTARGETSITE ]: Custom Action is starting... INFO : [03/31/2010 15:57:43:287] [SetTARGETSITE ]: CoInitializeEx - COM initialization Apartment Threaded... ERROR : [03/31/2010 15:57:43:290] [SetTARGETSITE ]: FAILED: -2147221164 ERROR : [03/31/2010 15:57:43:291] [SetTARGETSITE ]: Custom Action failed with code: '340' INFO : [03/31/2010 15:57:43:293] [SetTARGETSITE ]: Custom Action completed with return code: '340' Action ended 15:57:43: WEBCA_SetTARGETSITE. Return value 3. MSI (c) (8C:20) [15:57:43:297]: Doing action: FatalErrorForm Action start 15:57:43: FatalErrorForm.
I could see that the action WEBCA_SetTARGETSITE was failing. But I had not idea what was wrong, except that the term itself said Set Target Site failed. So I turned up to Google and landed on this blog post.
So the real problem is that my setup is unable to get the “Default Web Site” from IIS7.
The Solution
I installed the “IIS6 Metabase Compatibility” role using Role Manager as mentioned in the blog post and my setup started working. Existing software & scripts can interface with IIS7 only if the Metabase compatibility component is installed in IIS7.
Thanks to Galin Iliev.
[ObjectDataSource – MissingMethodException] Method not found: Void System.Web.UI.WebControls.Parameter.set_DbType (System.Data.DbType)
I recently faced this annoying error while working on an ASP.NET site. The problem only occurred with pages containing ObjectDataSource that took parameters.
After a lot of head scratching, I finally stumbled upon this thread. The problem is with the Type property of the ObjectDataSource. Removing the type property from the ObjectDataSource parameters would solve the problem.
Also the error here is misleading set_DbType is a property and not a method.
Writing Provider Independent .NET Data Access Code
Ever wanted to support different databases from different providers? Tired of writing different layers for different providers? Too much pain to maintain the code? Not anymore.
How many times have you been asked to support a different database when you have already written your data access layer for a specific database? We all know how painful it is. Every time you are asked to do so there is very less code that you can actually reuse. So what could be done minimize changes?
Normally our data access layer is tightly coupled with the database. Today when watching a screencast from DNRTV by Jean-Paul S. Boodhoo on design patterns he demoed a feature in .NET framework 2.0 called DbProviderFactory. He then dived into many other patterns but I will concentrate only on DbProviderFactory.
.NET 2.0 has factory classes which can determine the database type from a provided data provider name. So let me show you a quick example. To use this feature you have to add reference to the System.Configuration assembly.
Lets create an interface for our db provider class.
Provider Factory
ITestDbProviderFactory.cs
namespace NTierTest.Data
{
using System.Data;
/// <summary>
/// Database Provider Factory Class
/// </summary>
public interface ITestDbProviderFactory
{
#region Public Methods
/// <summary>
/// Creates an <see cref="IDbCommand"/>
/// </summary>
/// <returns></returns>
IDbCommand CreateCommand();
/// <summary>
/// Creates an <see cref="IDbConnection"/>
/// </summary>
/// <returns></returns>
IDbConnection CreateConnection();
#endregion
}
}
The ITestDbProviderFactory is a very simple interface which has two methods. CreateConnection will return a IDbConnection and CreateCommand will create a IDbCommand object.
Note we are returning abstract types. The provider specific classes like SqlConnection Or OracleConnection implement these abstract types.
Now lets create a class which will implement this interface
TestDbProviderFactory.cs
namespace NTierTest.Data
{
using System.Configuration;
using System.Data;
using System.Data.Common;
/// <summary>
/// A DbProvider Class that uses AbstractFactoryPattern To Return the Connection and Command
/// This implementation uses Mono State Pattern
/// </summary>
public class TestDbProviderFactory : ITestDbProviderFactory
{
#region Constants and Fields
/// <summary>
/// .NET FrameWork 2.0 Abstract Provider Factory
/// It is marked static .. to ensure one instance through out the application
/// </summary>
private static DbProviderFactory _frameworkProviderFactory;
/// <summary>
/// Loaded From The Configuration File
/// </summary>
private static ConnectionStringSettings _settings;
#endregion
#region Constructors and Destructors
/// <summary>
/// Static constructor will be called only once through out the application
/// </summary>
static TestDbProviderFactory()
{
_settings = ConfigurationManager.ConnectionStrings[1];
_frameworkProviderFactory = DbProviderFactories.GetFactory(_settings.ProviderName);
}
#endregion
#region Public Methods
/// <summary>
/// Returns a <see cref="IDbCommand"/> Object
/// </summary>
/// <returns>A Command Object</returns>
public IDbCommand CreateCommand()
{
return _frameworkProviderFactory.CreateCommand();
}
///<summary>
/// Return a <see cref="IDbConnection"/> Object
///</summary>
///<returns>Connection object</returns>
public IDbConnection CreateConnection()
{
IDbConnection connection = _frameworkProviderFactory.CreateConnection();
connection.ConnectionString = _settings.ConnectionString;
return connection;
}
#endregion
}
}
In this class we have created a private static instance of DbProviderFactory class which is a .net abstract factory class for doing provider related operations. We will use this class to create a provider specific connection and command object.
/// <summary>
/// Static constructor will be called only once through out the application
/// </summary>
static TestDbProviderFactory()
{
_settings = ConfigurationManager.ConnectionStrings[1];
_frameworkProviderFactory = DbProviderFactories.GetFactory(_settings.ProviderName);
}
We also have a private static ConnectionStringSettings object. We will use the ConfigurationManager class to get the connection string from the web.config/app.config file.
connectionString="Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient" />
We initialize the ConnectionStringSettings object and the DbProviderFactory object in the static constructor. To ensure one copy of these variables. The same could be done using Singleton pattern. But I prefer using the Monostatic pattern because we can acheive the same thing that we can acheive using the singleton pattern and the client will not know that he is using a single copy of the varialbles internally.
_settings = ConfigurationManager.ConnectionStrings[1]; reads the connection string settings from the configuration file. Notice I am getting the second connection string setting. Even if you have only one connection string setting defined in the web.config ASP.NET internally has a connection string already configured for the default asp.net database aspnet.mdf even if it does not exist.
On line number 49 we are instantiating the DbProviderFactory object using the System.Data.Common.DbProviderFactories class. We give the provider name to the GetFactory method of this class. This line will create a provider specific DbProviderFactory object for us.
I already have a connection string configured in my web.config file
So in the CreateConnection method we use the _frameworkProviderFactory.CreateConnection() method to get an IDbConnection object and then set the ConnectionString property of the created object to the ConnectionString property of the static ConnectionStringsSetting object.
public IDbCommand CreateCommand()
{
return _frameworkProviderFactory.CreateCommand();
}
public IDbConnection CreateConnection()
{
IDbConnection connection = _frameworkProviderFactory.CreateConnection();
connection.ConnectionString = _settings.ConnectionString;
return connection;
}
Data Access Layer
Now its time to write a data access layer. The interface for our data access layer contains only one method GetAllEmployees, which will return a DataTable.
IEmployeeRepository.cs
namespace NTierTest.Core
{
using System.Data;
/// <summary>
/// Employee repository
/// </summary>
public interface IEmployeeRepository
{
#region Public Methods
/// <summary>
/// Gets all employees.
/// </summary>
/// <returns>Employee data table</returns>
DataTable GetAllEmployees();
#endregion
}
}
After implementing this interface here is my data access layer
EmployeeRepository.cs
namespace NTierTest.Data
{
using System;
using System.Data;
/// <summary>
/// Employee tasks
/// </summary>
public class EmployeeRepository : IEmployeeRepository
{
#region Constants and Fields
private ITestDbProviderFactory _providerFactory;
#endregion
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the EmployeeRepository class.
/// Using poor mans dependency injection.
/// </summary>
public EmployeeRepository()
: this(new TestDbProviderFactory())
{
}
/// <summary>
/// Initializes a new instance of the EmployeeRepository class.
/// </summary>
/// <param name="provider"></param>
public EmployeeRepository(ITestDbProviderFactory provider)
{
this._providerFactory = provider;
}
#endregion
#region Public Methods
/// <summary>
/// Gets all employees.
/// </summary>
/// <returns>Employee data table</returns>
public DataTable GetAllEmployees()
{
try
{
DataTable rawData = new DataTable();
// Get the connection from the provider factory
using (IDbConnection connection = this._providerFactory.CreateConnection())
{
// create the command object using the conneciton object
IDbCommand command = connection.CreateCommand();
// Inline query has been used for the sake of this demo
// use stored procedure
command.CommandText = "Select * From Employees";
command.CommandType = CommandType.Text;
// open the connection
connection.Open();
// execute reader
IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
// load dataset from reader
// since reader cannot be used when the connection is closed I am using datatable
using (reader)
{
rawData.Load(reader);
}
}
// return the data
return rawData;
}
catch (Exception ex)
{
throw;
}
}
#endregion
}
}
We need a connection and command object to read data from our database, thats why I have created an instance of our provider factory. The data access layer will use this provider factory class to get the appropriate connection and command object.
private ITestDbProviderFactory _providerFactory;
Because our data access layer will be called from the service layer. I have created two constructor. One take a TestProviderFactory object and the empty constructor is used to feed the dependencies. This technique is called poor man’s dependency injection.
public EmployeeRepository() : this(new TestDbProviderFactory())
{
}
public EmployeeRepository(ITestDbProviderFactory provider)
{
this._providerFactory = provider;
}
In the GetAllEmployees method I create a DataTable object then get the connection from the _providerFactory.CreateConnection method. The CreateConnection method to our surprise return the correct connection object, in this case a SqlConnection.
Then I create IDbCommand object using the create connection, this way I don’t have to configure the connection property of the command.
I have used inline SQL query just for this demo sake. We should not use this in production. We should use stored procedure because sql for SQL Server and Oracle are different.
// create the command object using the conneciton object IDbCommand command = connection.CreateCommand(); // Inline query has been used for the sake of this demo // use stored procedure command.CommandText = "Select * From Employees"; command.CommandType = CommandType.Text; // open the connection connection.Open(); // execute reader IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
I use the DataTable.Load method to load the reader into the data table. Because the reader needs an open connection we cannot send reader between layers unless we have a persistent connection. Our service layer will use this data table object to create employee collection object.
// load dataset from reader
// since reader cannot be used when the connection is closed I am using datatable
using (reader)
{
rawData.Load(reader);
}
This completes our data access layer. Now lets write the service layer.
Service Layer
IEmployeeService.cs
namespace NTierTest.Core
{
using System.Collections.Generic;
///<summary>
///Employee Service contract
///</summary>
public interface IEmployeeService
{
#region Public Methods
/// <summary>
/// Gets all employees.
/// </summary>
/// <returns>List of Employees</returns>
IList<IEmployee> GetAllEmployees();
#endregion
}
}
The IEmployeeService interface is contains only one method GetAllEmployees which returns an IList of IEmployee.
EmployeeService.cs
namespace NTierTest.Service
{
using System;
using System.Collections.Generic;
using System.Data;
///<summary>
///Does all the employee related tasks
///</summary>
public class EmployeeService : IEmployeeService
{
//Method...
#region Public Methods
/// <summary>
/// Gets all employees.
/// </summary>
/// <returns>An <see cref="IList{T}"/> of <see cref="IEmployee"/></returns>
public IList<IEmployee> GetAllEmployees()
{
IEmployeeRepository employeeRepository = new EmployeeRepository();
IList<IEmployee> resutls = new List<IEmployee>();
foreach (DataRow row in employeeRepository.GetAllEmployees().Rows)
{
resutls.Add(
new Employee(
row["FirstName"].ToString(),
row["LastName"].ToString(),
DateTime.Parse(row["BirthDate"].ToString())));
}
return resutls;
}
#endregion
}
}
As you can see I create an instance of the EmployeeRepository class and make a call to the GetAllEmployees method and iterate over all the rows and then create Employee objects and add them to a IList IEmployees. Simple isn’t it?
Now what? Its all ready lets see it in action. I have already written a test to test the features.
namespace NTierTest.Test
{
using System;
using System.Collections.Generic;
/// <summary>
/// Employee Service Test Harness
/// </summary>
[TestFixture]
public class EmployeeTestServiceTest
{
#region Public Methods
/// <summary>
/// Gets all employees_ should get all employees.
/// </summary>
[Test]
public void TestGetAllEmployeesShouldGetAllEmployees()
{
IEmployeeService service = new EmployeeService();
IList<IEmployee> employees = service.GetAllEmployees();
foreach (IEmployee employee in employees)
{
Console.WriteLine(employee.FirstName);
}
Assert.IsTrue(employees.Count > 0);
}
#endregion
}
}
The test is very simple it creates an instance of the EmployeeService, Gets a list of employees and outputs it to the console.
I know this is not an actual way to do TDD. I am a beginner and I wanted to show that it actually creates instance of the correct provider, thats why I have not mocked anything.
Test Result
As you can see everything works as expected. Try it out yourself and say what do you think? Got thoughts? shout it out.
Download Source Code
ASP.NET MVC Preview 4 Released
The ASP.NET MVC team has released a new preview version of the framework. You can download the source code and the msi installer which includes the project templates from the asp.net codeplex site.
There are some new exiting features like AjaxHelpers, AjaxExtensions, Error handling, Caching, Authorization etc that has been added to the framework which I am very exited about. Finally with these features I can start my first real world ASP.NET MVC Project. Now it has those features which I needed to redo cfart.
ScottGu has made a very good blog post describing all the newly added features. Here is Part 1 of the series. I am waiting for the Part 2 where he is going to blog about the new AJAX features.
Scott Hanselman has already made a blog post about the new AJAX features in the new ASP.NET MVC Preview 4. You can read his post here.
Related Links
- New filters (OutputCache, HandleError, Authorize) and Membership provider by ScottGu
- Integration with ASP.NET AJAX by Scott Hanselman
- Finally TempData is test-friendly by Matt Hinze
- ComponentController has been removed, replaced by the RenderAction method by Rob Conery
- First impressions on the new RenderAction method, again by Matt Hinze
- together with some other small improvement by Matt Hawley
- Some other random thoughts:
- By Steven Walther
- By Ben Scheirman on how he plans to update CodeCampServer to P4