I recently decided to retire my WordPress blog and start a new blog on https://blog.lehmamic.ch.
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:
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:
- 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. - 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:
Databases in the cloud
I started to write about NoSQL in the official Zuehlke blog with my co-author Roman Kuczynski. We just published our first article, an introduction for databases in the cloud.
Enjoy 🙂
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.
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.
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
And also whether the collection has been created
db.getCollectionNames()
Has the data been inserted?
db.Customers.find()
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.
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
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.
Afterwards I created a folder for the database data (default ist c:\data\db).
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“
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
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
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()
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
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”.
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.
Troubles with byte arrays and Entity Framework
We encountered a tricky problem while filtering byte fields with the Entity Framework. I wrote a simple query, filtering entities, which has a byte value contained in a byte array.
byte[] list = new byte[] { 1, 2, 3}; efContext.MyEntities .Where(x => list.Contains(x.ByteField));
When I run this code it throwed an exception:
DbExpressionBinding requires an input expression with a collection ResultType.
Parameter name: input
I found out, that EF handles byte values in another way than the other simple type, because it is internally used for timestamps.
I resolved this problem by using a byte List.
List<byte> list = new List<byte>{ 1, 2, 3}; efContext.MyEntities .Where(x => list.Contains(x.ByteField));
This worked on my pc, so I though I solved the problem, but no, it only worked on my pc. We had a hard time to find out how we can fix this, nothing seems to work. At the end we just tried to use an Integer list instead of a byte list, even though the field is of type byte.
List<int> list = new List<int>{ 1, 2, 3}; efContext.MyEntities .Where(x => list.Contains((int)x.ByteField));
This works now, but I ’ am very disappointed of EF, such a simple thing just has to work!
String Calculator Kata in F#
I often make some code kata’s with my working colleagues to increase my skills, or have a look in new technologies and IDE’s.
This time we had the idea to make the very simple String Calculator kata with F# to get a first impression of this language.
First we created a Visual Studio solution with a C# test project and a F# library.
Than we created a unit test for the first case in the kata,an empty string will return 0.
[TestMethod] public void Add_NumbersIsEmptyString_ReturnsZero() { var target = new StringCalculator(); var result = target.Add(string.Empty); Assert.AreEqual(0, result); }
And we implemented the string calculator in F#
namespace FSharpStringCalculator type StringCalculator() = member this.Add(input : string) = 0
We had a very hard time to figure out how to write a method in F#, but finally it worked. It would be too much to explain all the single steps we made. I ‘ll show you our end result instead.
[TestMethod] public void Add_NumbersIsEmptyString_ReturnsZero() { var target = new StringCalculator(); var result = target.Add(string.Empty); Assert.AreEqual(0, result); } [TestMethod] public void Add_NumbersIs1Number_ReturnsNumber() { var target = new StringCalculator(); var result = target.Add("1"); Assert.AreEqual(1, result); } [TestMethod] public void Add_NumbersIs2Numbers_ReturnsAdd() { var target = new StringCalculator(); var result = target.Add("1,2"); Assert.AreEqual(3, result); }
And here our final implementation of the F# String Calculator.
namespace FSharpStringCalculator type StringCalculator() = member this.Add(input : string) = if System.String.IsNullOrWhiteSpace input then 0 else input.Split ',' |> Array.map (fun x -> System.Int32.Parse x) |> Array.sum
It was a very interesting experience and we think about to make another kata with F#.