Notes from Daily Encounters with Technology RSS 2.0
 
# Wednesday, June 08, 2011

One of the features introduced in Entity Framework 4 was support for foreign key properties in entity types. No matter what your opinion is about having foreign keys exposed by an ORM, there are some cases where it might be more practical or even more performant to use foreign key properties instead of navigation properties (e.g. when you are creating a new object with a reference for which you know the primary key value but don’t have a corresponding object in your ObjectContext). That’s the reason why it’s usually recommended to include foreign key columns in your model even though it will pollute your entity types with properties you might not need at all.

Update Wizard

But what if you decided not to include them in your model when you originally created it, but want to add them at a later time? Although the checkbox is enabled in the model Update Wizard which opens up when you want to Update Model from Database, its value only effects newly created entity types, but leaves existing entity types unchanged. Unless you feel comfortable deleting existing entity types and recreating them from database, you’ll have to add the properties by hand. Once you know how to do it, it’s just a matter of following a few simple steps. I’ll describe them on a simple example from Northwind database. I’ve only included three entity types: Category, Product and Supplier. We want to add CategoryID and SupplierID properties to the Product entity type.

Model without Foreign Key Properties

First add a new scalar property to the entity type:

  1. Right click on the Product entity type.
  2. Click on the Add > Scalar Property from the context menu.
  3. Click on the newly created Property and set its properties: Name to CategoryID, Nullable to True and Type to Int32.

CategoryID Properties Window

Next you need to map the database column to your new property:

  1. Open Mapping Details for Product entity type.
  2. Select the CategoryID : Int32 as Value / Property for the CategoryID : int column.

Product Mapping Details Window

Now it’s time to set up the referential constraint:

  1. Select the FK_Products_Categories association in the Model Browser.
  2. Open the Referential Constraint editor from its properties window.
  3. Select Category as Principal and CategoryID as Dependent Property.

Referential Constraint Editor

Only one step left, deleting the mapping of foreign key to the navigation property which is not allowed when you have a foreign key property in your entity type:

  1. Select the Category property of the Product entity type.
  2. Click on the Delete mappings link displayed in the Mapping Details window.

Category Mapping Details

You have to repeat the above steps for the SupplierID property and you have created a functionally identical model to the one automatically generated for you if you had selected to include foreign keys in the model before adding the tables to it.

Model with Foreign Key Properties

The above process is not only useful when you change your mind about the foreign key properties at a later time. You can also intentionally decide to add the foreign key properties only when you actually need them and avoid having redundant properties at the cost of the consistency of the model.

Wednesday, June 08, 2011 9:43:08 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | EF4
# Saturday, May 28, 2011

This week the annual Microsoft conference NT konferenca 2011 was taking place in Portorož. On Tuesday I had a talk there about the Windows API Code Pack. As promised, you can find the slides from this talk on SlideShare.

You can also download the sources for the sample project which is a working WPF MVVM image viewer application demonstrating the implementation of:

Saturday, May 28, 2011 12:03:33 PM (Central European Daylight Time, UTC+02:00)  #    Comments [0] - Trackback
Development | .NET | Interop | WPF | Downloads | Presentations | Sources
# Wednesday, March 23, 2011

It seems that no matter how much experience one has with .NET framework, there are still surprises awaiting him somewhere down the road. This time I’d like to point out an interesting behaviour of MethodInfo.Invoke many of you might not be aware of. I certainly wasn’t, until today.

Since this is well documented, I should start with a quote from the documentation for the parameters parameter: “An argument list for the invoked method or constructor. […] Any object in this array that is not explicitly initialized with a value will contain the default value for that object type. For reference-type elements, this value is null. For value-type elements, this value is 0, 0.0, or false, depending on the specific element type.”

What exactly does this mean? If you pass a null as a value for a value-type parameter, the call won’t fail as you might have expected. Instead, the default value for that type will be set as the parameter value.

The following short sample demonstrates this behaviour:

public void WriteValue(int value)
{
    Console.WriteLine("value = {0}", value);
}

public static void Main(string[] args)
{
    // this will result in a compile error:
    // Argument 1: cannot convert from '<null>' to 'int'
    WriteValue(null);

    // this will output:
    // value = 0
    Type type = typeof(Program);
    MethodInfo method = type.GetMethod("WriteValue");
    method.Invoke(new Program(), new object[] { null });

    // this will throw a RuntimeBindingException:
    // The best overloaded method match for 'Program.WriteValue(int)' has some invalid arguments
    dynamic obj = new Program();
    obj.WriteValue(null);
}

Obviously calling the method directly with a null value won’t even compile (unless you change the parameter type to Nullable<int>). The Reflection based call succeeds by passing the default value (0 for int) as the parameter value. The dynamic type doesn’t exhibit this behaviour – the call fails with a runtime exception.

Wednesday, March 23, 2011 9:21:12 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET
# Wednesday, March 09, 2011

When architecting solutions using Workflow Foundation it is typically necessary to provide information to individual activities. But apart from standard input arguments being passed to the workflow or originating from previously executed activities, which can best be modelled using InArgument<> properties, there is often also a need to access some kind of contextual information in the activity. In this post I’m going to discuss three different approaches to providing such context to a custom workflow activity.

The most obvious and simple way of achieving this that comes to mind is of course by declaring another InArgument<> of the required type in your activity. Just make sure that the type you are using is decorated with SerializableAttribute if you plan to use persistence. The solution is far from elegant, though. Every time such an activity will be used in the workflow designer, the additional argument will have to be set to the correct value. Typically you’ll have to create an in argument in your workflow and set it to correct value when initializing the workflow. It is doable but also very tedious. I certainly don’t suggest doing it this way if the workflows are going to be designed by your end users. It can be a nice shortcut in specific well managed scenarios when you don’t need a more sophisticated solution.

// Custom activity class
public class ArgumentContextActivity : CodeActivity
{
    // Input argument with context information
    public InArgument<ContextType> ContextArgument { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        // Retrieve the context value
        ContextType contextValue = ContextArgument.Get(context);
    }
}

// Test code for running the workflow
[Test]
public void RunArgumentContextWorkflow()
{
    // The context needs to be provided as an input argument
    var inputs = new Dictionary<string, object>() { { "Context", new ContextType() } };
    var results = WorkflowInvoker.Invoke(new ArgumentContextWorkflow(), inputs);
}

ArgumentContextWorkflow definition 

A better approach would be using execution properties in combination with a special scope activity. This pattern is already being implemented by CorrelationScope, one of the built-in activities in .NET Framework 4. The basic idea is that the scope activity sets the context values as a named property which can be later retrieved by all its child activities. Ignoring the fact that the property isn’t strongly typed and can only be accessed from the property collection based on its string value key, the solution is very suitable in cases which allow the scope activity to generate the context value itself based on the provided input arguments, typically taking care of different independent aspects, such as logging, transactions, security, etc. Again, don’t forget about the SerializableAttribute decoration on the context type for persistence to work.

// The scope activity needs a simple designer to add a child activity
[Designer(typeof(PropertyContextScopeDesigner))]
public class PropertyContextScope : NativeActivity
{
    // Hide ChildActivity from the properties window
    [Browsable(false)]
    public Activity ChildActivity { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        // Create the context and set the property
        context.Properties.Add("Context", new ContextType());
        // Run child activity
        context.ScheduleActivity(ChildActivity);
    }
}

// Custom activity to be used inside the scope
public class PropertyContextActivity : NativeActivity
{
    protected override void Execute(NativeActivityContext context)
    {
        // Retrieve the context value from the property
        ContextType contextValue = (ContextType)context.Properties.Find("Context");
    }
}

// Test code for running the workflow
[Test]
public void RunPropertyContextWorkflow()
{
    // No need to provide an input argument
    var results = WorkflowInvoker.Invoke(new PropertyContextWorkflow());
}

PropertyContextWorkflow definition 

The final option for providing context are workflow instance extensions. You can create them by implementing the IWorkflowInstanceExtension interface. Instead of instantiating the context type inside a special activity, you need to provide an instance of it or a delegate for creating a new instance to the workflow runtime, i.e. add one or the other to either the Extensions property of the WorkflowApplication and WorkflowInvoker class or the WorkflowExtensions property of the WorkflowServiceHost class. In both cases you need direct access to the hosting class, meaning that you need to take care of the workflow hosting yourself. If that is not the case your last resort is to provide the delegate for creating the extension inside the overridden CacheMetadata method of your NativeActivity by calling AddDefaultExtensionProvider<> method. No matter how you ensure the extension, you can then access it inside your activity by calling the GetExtension<> method on your ActivityContext class.

// Instance extension class
public class ExtensionContextExtension : IWorkflowInstanceExtension
{
    private ContextType context = new ContextType();

    // Context property for the activity
    public ContextType Context
    {
        get
        {
            return context;
        }
    }

    public IEnumerable<object> GetAdditionalExtensions()
    {
        return null;
    }

    public void SetInstance(WorkflowInstanceProxy instance)
    { }
}

// Custom activity depending on the extension
public class ExtensionContextActivity : CodeActivity
{
    protected override void CacheMetadata(CodeActivityMetadata metadata)
    {
        // Activity should indicate it requires the extension
        metadata.RequireExtension<ExtensionContextExtension>();
    }

    protected override void Execute(CodeActivityContext context)
    {
        // Retrieve the context value from the extension
        ContextType contextValue = context.GetExtension<ExtensionContextExtension>().Context;
    }
}

// Test code for running the workflow
[Test]
public void RunExtensionContextActivity()
{
    // The activity can be run standalone
    WorkflowInvoker invoker = new WorkflowInvoker(new ExtensionContextActivity());

    // Add extension to the runtime before running the workflow
    invoker.Extensions.Add<ExtensionContextExtension>(() => new ExtensionContextExtension());
    var results = invoker.Invoke();
}

I like the last approach best for several reasons:

  • It provides strongly typed access to your context class.
  • Not only is it suitable for providing different aspects as contexts created inside the workflow itself, but it also enables communication out of the workflow runtime directly from the activity because the class can be created outside the runtime and as such can contain references to external objects.
  • Last but not least the context class doesn’t need to be serialized as it is created again after the persisted workflow gets rehydrated.

As always make sure you choose the approach which suits your problem best, now that you are aware of all the available options.

Wednesday, March 09, 2011 9:18:22 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET | WF4
# Friday, March 04, 2011

One of the changes in .NET Framework 4 was the retirement of Code Access Security (CAS). Until recently this was something, I have only read about at the time of release, but it didn’t have any effect on my day to day work. Therefore I was even more surprised that an application which has recently been migrated from .NET 2.0 to .NET 4 suddenly failed to start from the network drive while working flawlessly from the local machine. Wasn’t this problem already resolved with the release of .NET Framework 3.5 SP1 when the FullTrust set of permissions was granted to LocalIntranet zone by default? Obviously not. The issue certainly demanded further investigation.

While the exception thrown by the runtime only hinted at some assembly loading related issue (System.IO.FileLoadException: Could not load file or assembly '<assembly>' or one of its dependencies. Operation is not supported.), its inner exception was much more informative and already pointed at the solution (System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.).

The link included in the exception message points to the documentation for the <loadFromRemoteSources> configuration element which provides the solution for the problem – just add this element to the configuration file of your executable and you’re done:

<configuration>
  <runtime>
    <loadFromRemoteSources enabled="true" />
  </runtime>
</configuration>

Though, the page does a really bad job at explaining why this is necessary at all. Sure, it’s something related to loading assemblies from zones which aren’t fully trusted, but it doesn’t happen always. If you deploy an application which references a library in the same folder to a network drive, it will work flawlessly. But if you try to load that same library using Assembly.LoadFrom() instead of referencing it, the problem will manifest itself. The reason being that this method implicitly uses CAS policy. The details are thoroughly discussed in the linked article but essentially the exception is thrown because otherwise the assembly might be loaded with full trust in .NET 4 which would be granted a more restricted permission set in .NET 2.0 because the CAS policy is now disabled. This could be a potential security vulnerability for applications developed for the old framework.

This also means that there is another way to fix the issue in .NET 4 – by enabling the CAS policy with the <NetFx40_LegacySecurityPolicy> configuration element (strangely the <legacyCasPolicy> configuration element has the same effect although it’s not documented anywhere – remains from the beta period, perhaps?):

<configuration>
  <runtime>
    <NetFx40_LegacySecurityPolicy enabled="true" />
  </runtime>
</configuration>

Though, there is a difference between both solutions:

  • The first one enables loading of all assemblies from remote locations (other than MyComputer zone) with full trust permission set. Use this only if you know exactly which assemblies your application will be loading, i.e. you have full control over their location and also over the assembly names being passed to the Assembly.LoadFrom() method.
  • The second one reverts the security model back to the .NET 2.0 mode, i.e. you have the same control over the granted permission sets as in .NET 2.0 by using the Code Access Security policies.

Keep in mind that both of these solutions should only be used temporarily and in the long run the code should be migrated to the simple sandboxing model, available since .NET 2.0 and the only remaining one in .NET 4.

Friday, March 04, 2011 9:51:24 PM (Central European Standard Time, UTC+01:00)  #    Comments [0] - Trackback
Development | .NET
Sponsored Ads

About Me
Twitter
I really need to give this a try: Notify Property Weaver : http://t.co/WRiDR7Rt 1 day ago
The Web is the new Terminal: Are you using the Web's Keyboard Shortcuts and Hotkeys? http://t.co/4PSPFgIy via @shanselman 1 day ago
Do Hard Things | Sealed Abstract http://t.co/6LDRAcrb (via Instapaper) 1 day ago
Potepanja v naravi: Abram na Nanosu http://t.co/vtlUEWJg 1 day ago
@MladenPrajdic @andrejt use the middle mouse button then 3 days ago
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

All Content © 2012, Damir Arh, M. Sc. Send mail to the author(s) - Privacy Policy - Sign In
Based on DasBlog theme 'Business' created by Christoph De Baene (delarou)
Social Network Icon Pack by Komodo Media, Rogie King is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.