Handling CORS with ASP vNext

I recently tried out Ionic with a back-end written with ASP vNext. While Ionic is already in a very stable state, ASP vNext just started and did not pass the alpha state yet.

Almost every browser checks the origin of the HTTP requests. If we make some AJAX calls, we’re running into a problem if the back-end is hosted on a different URL and this is always the case if we develop mobile apps with Ionic. Anyway, there is a technique called Cross-Origin Resource Sharing (CORS), which allows us to access a back-end from a different URL.
ASP WebApi has a build in mechanism to enable CORS, but since ASP gets completely rewritten in ASP vNext a lot of functionality does not exist yet, including CORS handling.

So we have to implement our own CORS. We need to add three headers on the HTTP Responses in our ASP vNext back-end:

  • Access-Control-Allow-Origin – the allowed origin of the request
  • Access-Control-Allow-Methods – the allowed method of the request
  • Access-Control-Allow-Headers – the allowed headers of the request

Our first approach was to introduce an action filter attribute, but since we had some routing problem we ended up writing a custom middleware.

public class Startup
{  
	public void Configure(IBuilder app)
    {
		// ...
			
        app.Use((context, next) =>
            {
                context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
                context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });
				context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "*" });
                return next();
            });
				
		// ...
    }
}

The header value “*” allows everything by default, you also can enable CORS more specific if required.

External sources:

Advertisements

Extending CS file properties in a VSPackage

To exclude files from StyleCop analysis in legacy project, we have to add an <ExcludeStyleCop>true</ExcludeStyleCop> element for every file in the csproj document. It is quite tiring to switch that off after the file has been cleaned up so i decided to write a Visual Studio extension which allows my to set the ExcludeStyleCop attribute via Visual Studio property grid.

Visual Studio SDK Extender Provider

I started with an empty VSPackage and tried to figure out how I can extend the cs file property grid. To achieve this I had to implement an extender provider, similar tho the WinForms extended properties.

public class ExcludeStyleCopExtenderProvider : IExtenderProvider
 {
     public const string SupportedExtenderName = "ExcludeStyleCopExtender";
     public const string SupportedExtenderCATID = VSConstants.CATID.CSharpFileProperties_string;
     private const string CSharpFileExtension = ".cs";

     public object GetExtender(string ExtenderCATID, string ExtenderName, object ExtendeeObject, IExtenderSite ExtenderSite, int Cookie)
     {
         IExcludeStyleCopExtender extender = null;

         if (this.CanExtend(ExtenderCATID, ExtenderName, ExtendeeObject))
         {
             var fileName = ExtendeeObject.GetPropertyValue("FileName");
             extender = new ExcludeStyleCopExtender(fileName, ExtenderSite, Cookie);
         }

         return extender;
     }

     public bool CanExtend(string ExtenderCATID, string ExtenderName, object ExtendeeObject)
     {
         return ExtenderName == SupportedExtenderName // check if the correct extener is requested
             && string.Equals(ExtenderCATID, SupportedExtenderCATID, StringComparison.OrdinalIgnoreCase) // check if the correct CATID is requested
             && string.Equals(ExtendeeObject.GetPropertyValue("ExtenderCATID"), SupportedExtenderCATID, StringComparison.OrdinalIgnoreCase) // check whether the extended object really has this CATID
             && string.Equals(ExtendeeObject.GetPropertyValue("Extension"), CSharpFileExtension, StringComparison.OrdinalIgnoreCase); // check whether the file extension is '.cs'
     }
}

Two things made a lot of trouble:

  1. What is the right CATID? Here you’ll have o try it out. The available CATIDs you can get from the PrjBrowseObjectCATID class, or alternatively from the VSConstants.CATID class. I use the
    VSConstants.CATID.CSharpFileProperties_string constant for my purpose.
  2. Of what type is the ExtendeeObject and how can I cast it? It is a COM object. It is possible to cast it to the FileProperties2 interface, but since I also need to retrieve the ExtenderCATID from the ExtendeeObject, so I used the TypeDescriptor to resolve the values. Another option would be to use the dynamic keyword, but I don’t like this, since it is not type save.

In the code snippet above some logic is hidden within extension methods, see their implementation here:

public static class TypeDescriptorSupport
 {
     public static T GetPropertyValue(this object source, string propertyName)
     {
         if (source == null)
         {
             throw new ArgumentNullException("source");
         }

         if (propertyName == null)
         {
             throw new ArgumentNullException("propertyName");
         }

         object value = null;

         PropertyDescriptor property = TypeDescriptor.GetProperties(source)[propertyName];
         if (property != null)
         {
             value = property.GetValue(source);
         }

         return value != null ? (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture) : default(T);
     }
 }

Extender Class

The extender returns the extender instance. It is important that this extender object is com visible. For that create an interface containing the properties you want to add to the property grid.

[CLSCompliant(false)]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IExcludeStyleCopExtender
{
    [DefaultValue(false)]
    [DisplayName("Exclude StyleCop")]
    [Category("StyleCop")]
    [Description("Specifies that the file is exculded from the StyleCop source analysis.")]
    bool ExcludeStyleCop { get; set; }
}

You also can use the normal designer attributes used for the standard WinForms property grid.

Afterwards create a derived class from this interface.

[CLSCompliant(false)]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public sealed class ExcludeStyleCopExtender : IDisposable, IExcludeStyleCopExtender
{
    private readonly ProjectItem projectItem;
    private readonly IExtenderSite extenderSite;
    private readonly int cookie;

    private bool disposed = false;

    public ExcludeStyleCopExtender(string fileName, IExtenderSite extenderSite, int cookie)
    {
        if (fileName == null)
        {
            throw new ArgumentNullException("fileName");
        }

        if (extenderSite == null)
        {
            throw new ArgumentNullException("extenderSite");
        }

        this.extenderSite = extenderSite;
        this.cookie = cookie;

        // resolve the project item from the file name
        var dte = (DTE)Package.GetGlobalService(typeof(DTE));
        this.projectItem = dte.Solution.FindProjectItem(fileName);
    }

    ~ExcludeStyleCopExtender()
    {
        this.Dispose(false);
    }

    [DefaultValue(false)]
    [DisplayName("Exclude StyleCop")]
    [Category("StyleCop")]
    [Description("Specifies that the file is exculded from the StyleCop source analysis.")]
    public bool ExcludeStyleCop
    {
        get
        {
            return this.projectItem.GetItemAttribute("ExcludeStyleCop");
        }

        set
        {
            this.projectItem.SetItemAttribute("ExcludeStyleCop", value);
        }
    }

    public void Dispose()
    {
        this.Dispose(true);

        // take the instance off of the finalization queue.
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        // check to see if Dispose has already been called.
        if (!this.disposed)
        {
            // if IDisposable.Dispose was called, dispose all managed resources
            if (disposing)
            {
                // free other state (Managed objcts)
                if (this.cookie != 0)
                {
                    this.extenderSite.NotifyDelete(this.cookie);
                }
           }

            // if Finilize or IDisposable.Dispose, free your own state (unmanaged objects)
            this.disposed = true;
        }
    }
}

Important is, that the extenderSite gets notified when the extender instance is destroyed, otherwise it can crash Visual Studio.

Persist ProjectInfo properties

I also hided some code behind extension methods, here the project item attributes comes in place. Here is described how we can persist custom projectItem attributes.

public static class ProjectItemSupport
{
    public static void SetItemAttribute<T>(this ProjectItem item, string attributeName, T value)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }

        if (attributeName == null)
        {
            throw new ArgumentNullException("attributeName");
        }

        IVsHierarchy hierarchy = item.GetProjectOfUniqueName();
        var buildPropertyStorage = hierarchy as IVsBuildPropertyStorage;
        if (buildPropertyStorage != null)
        {
            uint itemId = hierarchy.ParseCanonicalName(item);
            var attributeValue = (string)Convert.ChangeType(value, typeof(string), CultureInfo.InvariantCulture);

            int hresult = buildPropertyStorage.SetItemAttribute(itemId, attributeName, attributeValue);
            if (hresult != 0)
            {
                string message = string.Format(CultureInfo.InvariantCulture, "Could not set the value {0} for item attribute {1}", attributeValue, attributeName);
                throw new InvalidOperationException(message);
            }
        }
    }

    public static T GetItemAttribute<T>(this ProjectItem item, string attributeName)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }

        if (attributeName == null)
        {
            throw new ArgumentNullException("attributeName");
        }

        string value = string.Empty;
        IVsHierarchy hierarchy = item.GetProjectOfUniqueName();

        var buildPropertyStorage = hierarchy as IVsBuildPropertyStorage;
        if (buildPropertyStorage != null)
        {
            uint itemId = hierarchy.ParseCanonicalName(item);

            int hresult = buildPropertyStorage.GetItemAttribute(itemId, attributeName, out value);
            if (hresult != 0)
            {
                string message = string.Format(CultureInfo.InvariantCulture, "Could not get the value from the item attribute {0}", attributeName);
                throw new InvalidOperationException(message);
            }
        }

        return string.IsNullOrWhiteSpace(value) ? default(T) : (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
    }

    private static IVsHierarchy GetProjectOfUniqueName(this ProjectItem item)
    {
        IVsHierarchy hierarchy;
        var solution = (IVsSolution)Package.GetGlobalService(typeof(SVsSolution));
        int hresult = solution.GetProjectOfUniqueName(item.ContainingProject.UniqueName, out hierarchy);
        if (hresult != 0)
        {
            string message = string.Format(CultureInfo.InvariantCulture, "Could not retrieve project hierarchy with name {0}", item.ContainingProject.UniqueName);
            throw new InvalidOperationException(message);
        }

        return hierarchy;
    }

    private static uint ParseCanonicalName(this IVsHierarchy hierarchy, ProjectItem item)
    {
        uint itemId;
        var fullPath = (string)item.Properties.Item("FullPath").Value;
        int hresult = hierarchy.ParseCanonicalName(fullPath, out itemId);
        if (hresult != 0)
        {
            string message = string.Format(CultureInfo.InvariantCulture, "Could not parse canonical name {0}", fullPath);
            throw new InvalidOperationException(message);
        }

        return itemId;
    }
}

Register the ExtenderProvider

Now e have to register our extender provider.

this.extensionManager = this.GetService(typeof(ObjectExtenders)) as ObjectExtenders;
if (this.extensionManager == null)
{
    throw new InvalidOperationException("Failed to resolve the extension manager.");
}

this.excludeStyleCopExtenderProviderCookie = this.extensionManager.RegisterExtenderProvider(
    ExcludeStyleCopExtenderProvider.SupportedExtenderCATID,
    ExcludeStyleCopExtenderProvider.SupportedExtenderName,
    new ExcludeStyleCopExtenderProvider());

Note that Visual Studio will not initialize the VSPackage when you have no menu items, or other user interface extension registered. But you can set the autoload attribute to define when Visual Studio shall load package.

I hope I could make your life easier by sharing my knowledge.

Sources:

First steps with MongDB – part #2

In part #1 of this article series I wrote about my experience trying out MongoDB. In part #2 I’m going to show you, how to connect to MongoDB, query and persist some data within a .Net application.

First I created a new console application project.
Create new console application

Than open the NuGet package manager and install the Official MongoDB C# driver or download it from here and add a reference to the project.
Add MongoDB csharp driver

Now I created a Customer entity class. Important is, that entity classes have an Id property. It does not have to be of type Guid, but it makes life easier since it can auto generate the id without any further actions.

public class Customer
{
   public Guid Id { get; set; }
   public string FirstName { get; set; }
   public string LastName { get; set; }
}

Open a MongoDB server connection and retrieving the database is quite easy.

const string connectionString = "mongodb://localhost";

var client = new MongoClient(connectionString);
var server = client.GetServer();
var database = server.GetDatabase("MongoDBSample");

Fine we got our database, but now it is time to insert some data. For this I also need to use a data collection.

var collection = database.GetCollection("Customers");

var customerId = new Guid("326bd08e-2ab4-40ce-9e76-a0ef2277fb8d");
var entity = new Customer { Id = customerId, FirstName = "Tom", LastName = "Sawyer" };

collection.Insert(entity);

Let’s see if the database got created, the command you already know from the first article.

show dbs

Check created mongoDB database

And also whether the collection has been created

db.getCollectionNames()

Check created MongoDB collection

Has the data been inserted?

db.Customers.find()

Check inserted MongoDB data

Fine everything seems to work. Let’s modify the inserted data.

Customer myCustomer = collection.FindOneById(customerId);
myCustomer.LastName = "Riddle";
collection.Save(myCustomer);

And check again if the data has been updated. You already should know the command so I don’t write it again.

Check updated MongoDB data

How cool, I also can use LinQ to query the data.

var availableCustomers = collection.AsQueryable()
   .Where(c => c.LastName == "Riddle")
   .ToArray();

To round up my small demo, I remove the created database with the MongoDB shell.

db.dropDatabase()
show dbs

Drop MongoDB database

This is the end of this article series about my first steps with MongoDB, thanks for reading.

First steps with MongDB – part #1

It is long ago I wrote my last post, so it is time to start writing again. I talked about NoSQL in the Zuehlke technology group event start of February 2013. For preparation I played a bit with MongoDB, a well known document based database. I’d like to share this experience with you guys out there.

Installation
First I downloaded the latest release at http://www.mongodb.org/downloads and unzip it’s content to a local folder.

Unzip MongoDB

Afterwards I created a folder for the database data (default ist c:\data\db).

Create MongoDB data folder

Start MongoDB
This is all you need to install MongoDB. Now I start the MongoDB demon with the command:

mongod.exe –dbpath “C:\Data\MongoDB“

Run MongoDB demon

Attention, there will be a firewall message, click on “Allow Access”.

With a new PowerShell window we start the MongoDB shell with the command:

mongo.exe

Start MongoDB shell

The test database
The MongoDB shell is based on JavaScript instead of an SQL query language, so we can use JavaScript commands to manipulate and query data. Lets see how this works.

The MongoDB shell will connect to the default database “test” even though this database does not exist yet. We can list out the existing databases with the command:

show dbs

List empty MongoDB

As we can see, only the metadata database “local” is available. Remember, the shell is connected to the database “test”. This database will be created as soon as we insert some data. Collections are kind of a data pot similar to tables in MSSQL. So lets insert some data into the collection “test” and make a query on this collection:

db.test.save( { a : 1 } )
db.test.find()

Insert MongoDB test data

We can see, that our data has been inserted and an id has been automatically generated for us. Now the “test” database should exist.

show dbs

List test database

This was the first part of my MongoDB trial. You can find the official tutorial here.

Continue reading in part #2 (Coming soon) . I will show how to use the MongoDB C# driver in a small .Net application.

Continuos sql server deployment made easy

The team leader decided to provide fully migrated database backups for the project stakeholders . Actually a nice turn to give them the possibility to continuosly play with the Teams daily increment. John got the job to migrate the latest test databases to the daily builds. So every day he made a round asking the developers, which database changes they made and spent at least an hour to provide the backup files every day.

One day some stakeholder come and ask: “Hey where are the data rows I produced yesterday?”, another day  someone else comes and want his database updated, but John cannot identify which version it has because some migration steps where missing and so on…

Sounds familiar right? These are problems I already encountered in several Projects. Resently I got to know a technique called Coninuous SQL Server Deployment.

First of all, every database change results in a tiny SQL script:

- 0001_CreateTables
- 0002_InserDefaultMasterData
- 0003_UpdateUserTable
- 0004_CreateLogTable

Than we use a library called DBUP to execute the upgrade process.

 var upgrader = DeployChanges.To
            .SqlDatabase(connectionString)
            .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly())
            .LogToConsole()
            .Build();

    var result = upgrader.PerformUpgrade();

DBUP will create a table called SchemaVersions and insert each executed script into this table. The next time only the scripts which are not present within the versions table are executed.

Problem solved, everybody can keep his data and it is only a small effort to create These tiny upgrade scripts compared to one big migration step.

You can find the library under:
http://dbup.github.com/

Activate a Windows 8 Enterprise installation without existing DNS

When I tried to activate my Windows 8 Enterprise Installation within my VM, I got an error “DNS name does not exist”.

Error Message

I found the solution for this Problem on this page:
http://answers.microsoft.com/en-us/windows/forum/windows_cp-windows_install/i-have-windows-8-enterprise-installed-and-it-did/05e65233-9644-4818-b9a7-ffcec05fa99f

Open the powershell and type:

slui 3

There you can enter your Serial key.

Activate Screen