OrchardProject + WebApi = interesting

Update: Code for the module is available on GitHub.

Orchard is really cool for CMS solutions, however, I am learning more about dependency injection, inversion of control, etc, and what I see in orchard is very interesting.

Asp.net mvc does well to de-couple pieces of the application when it comes to handling routes, but something is still missing. With asp.net mvc, you have to deploy these pieces along with the application, and perhaps discover them with mef, autofac, etc, but what about updates? If you wanted to update your modules, you have to FTP them to the application root, and re-write the dlls.

Is there an easier way to deploy updates, what about an application that could update itself????????

Nuget to the rescue

Phil Hack (@Haacked) wrote something on his blog about building a self-updating site using nuget (link.) This is really cool because it allows you to package up an application update, and the application can update itself.

However… the scenario I am going for is really about multiple modules.

Orchard CMS

Orchard uses Nuget, and is fully able to handle modules. From inside of the orchard application’s dashboard, I can install modules, as well as updates to those modules. The modules can also state dependencies, which are installed automatically.

Getting Started

To get started, first download an installation of Orchard CMS.  I used the core recipe, as this is going to be more of a rest endpoint:

Then you will want to enable the code-generation module.  Now you can create a module like using the orchard.exe command that should be in the bin folder of your application.  I created a module called myRestfulModule:

Orchard just generated a module for us, and placed it in the /Modules directory inside the Orchard web application’s folder structure.  This means that the module is already installed, just not yet activated.

I looked in visual studio, and my new module was not included automatically in the solution, so I added it.  Here is my module: as you can see, it already has references to orchard dlls.

I tweaked the module.txt file to look something like this:

Name: myRestfulModule
AntiForgery: enabled
Author: Jeremiah Redekop
Website: http://blogs.geniuscode.net/JeremiahRedekop
Version: 0.5.0
OrchardVersion: 0.5.0
Description: A sample restful endpoint using wcfwebapi
Features:
    myRestfulModule:
        Description: Hello world using rest from inside orchard.

Which then gives Orchard the ability to render the module in the admin module library like this:

We can just go ahead and enable the module. Now let’s get the module doing something interesting. Go ahead and use nuget to install WebApi.All, which is good to start. (By the way, I started out with this tutorial on the orchard site, but had to tweak it to work with webapi.)

The details

We need to make a few tweaks:

  • Orchard ROOT: Modify Web.config on Orchard application root – allow asp.net compatibility
  • MODULE: Create Rest Endpoint – same as before with one tweak
  • MODULE: Create Route Provider – helps orchard with routing requests to our module

Orchard Application Web.config:

  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
  </system.serviceModel>

This is the Rest endpoint. I am using the Fabricator library just to mock up a whole bunch of people. I need this class to implement IDependency for Orchard to create it properly

[ServiceContract]
    public class PeopleService
        : IDependency // required for orchard
    {
        private static readonly List _people = Fabrication.Fabricator.Generate(500).ToList();

        [WebGet]
        public IQueryable GetPeople()
        {

            return _people.AsQueryable();
            //return new EnumerableQuery(new Person[]{});
        }

        [WebGet(UriTemplate = "{name}")]
        public Person GetPerson(string name) {
            return _people.Single(p=> p.Name == name);
        }
    }

Here is the route provider that uses the orchard convention of being at the root of your module. Orchard will use this to route requests to the rest endpoint. If you look at the extenson method, the goodies are there.

    public class Routes : IRouteProvider {
        private static readonly ServiceRoute _route = MapServiceRoute(typeof (PeopleService), "myRestfulModule/People");
        public IEnumerable GetRoutes() {
            return new[] {
                new RouteDescriptor {
                    Priority = 1,
                    Route = _route
                }
            };
        }

        public void GetRoutes(ICollection routes) {
            foreach (var routeDescriptor in GetRoutes())
                routes.Add(routeDescriptor);
        }

        private static ServiceRoute MapServiceRoute(Type serviceType, string routePrefix, HttpConfiguration configuration = null, object constraints = null, bool useMethodPrefixForHttpMethod = true)
        {
            if (configuration == null)
                configuration = new WebApiConfiguration(useMethodPrefixForHttpMethod);

            var serviceHostFactory = new HttpServiceHostFactory { Configuration = configuration };
            var webApiRoute = new WebApiRoute(routePrefix, serviceHostFactory, serviceType) { Constraints = new RouteValueDictionary(constraints) };
            return webApiRoute;
        }
    }

Now by navigating to the url, you can see the end result.

Conclusion

This is a prototype of using an orchard module to expose rest endpoints.  The main benefit, I believe, is the ability to expose and update endpoints independant of any application code.  Once you deploy your orchard application, you don’t have to redeploy.  All you have to do is publish updates to your modules, and then install them from the application’s admin panel.

There are downsides, such as having a dependency on Orchard, but the current release is production-ready.

The located assembly’s manifest definition does not match the assembly reference.

Sometimes I get errors like these:

Could not load file or assembly ‘gcRelayVisitor’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0×80131040)

You need to do a few things to turn on Assembly Load Trace:

First, modify the registry in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Fusion by adding:

  • DWORD ForceLog set value to 1
  • DWORD LogFailures set value to 1
  • DWORD LogResourceBinds set value to 1

Then RESTART your pc.

Now we’re ready to run fuslogvw (docs). I then got this output:

*** Assembly Binder Log Entry  (10/27/2011 @ 4:55:05 PM) ***

The operation failed.
Bind result: hr = 0x80131040. No description available.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  C:\Program Files\Common Files\Microsoft Shared\DevServer\10.0\WebDev.WebServer40.exe
--- A detailed error log follows.

=== Pre-bind state information ===
LOG: User = WIN-R2MC10THE6H\Jeremiah Redekop
LOG: DisplayName = gcRelayVisitor
 (Partial)
WRN: Partial binding information was supplied for an assembly:
WRN: Assembly Name: gcRelayVisitor | Domain ID: 2
WRN: A partial bind occurs when only part of the assembly display name is provided.
WRN: This might result in the binder loading an incorrect assembly.
WRN: It is recommended to provide a fully specified textual identity for the assembly,
WRN: that consists of the simple name, version, culture, and public key token.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue.
LOG: Appbase = file:///C:/Users/Jeremiah Redekop/documents/visual studio 2010/Projects/ProductCatalog/ProductCatalog/
LOG: Initial PrivatePath = C:\Users\Jeremiah Redekop\documents\visual studio 2010\Projects\ProductCatalog\ProductCatalog\bin
LOG: Dynamic Base = C:\Users\Jeremiah Redekop\AppData\Local\Temp\Temporary ASP.NET Files\root\a9caded3
LOG: Cache Base = C:\Users\Jeremiah Redekop\AppData\Local\Temp\Temporary ASP.NET Files\root\a9caded3
LOG: AppName = cc40dd82
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Jeremiah Redekop\documents\visual studio 2010\Projects\ProductCatalog\ProductCatalog\web.config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/Jeremiah Redekop/AppData/Local/Temp/Temporary ASP.NET Files/root/a9caded3/cc40dd82/gcRelayVisitor.DLL.
LOG: Attempting download of new URL file:///C:/Users/Jeremiah Redekop/AppData/Local/Temp/Temporary ASP.NET Files/root/a9caded3/cc40dd82/gcRelayVisitor/gcRelayVisitor.DLL.
LOG: Attempting download of new URL file:///C:/Users/Jeremiah Redekop/documents/visual studio 2010/Projects/ProductCatalog/ProductCatalog/bin/gcRelayVisitor.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\Jeremiah Redekop\documents\visual studio 2010\Projects\ProductCatalog\ProductCatalog\bin\gcRelayVisitor.dll
LOG: Entering download cache setup phase.
LOG: Assembly Name is: gcRelayVisitor35, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
WRN: Comparing the assembly name resulted in the mismatch: NAME
ERR: The assembly reference did not match the assembly definition found.
ERR: Setup failed with hr = 0x80131040.
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

So for me it seems like the assembly name is gcRelayVisitor35, while my application is expecting gcRelayVisitor. Uhoh. Here is the project file for my library:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{D335EFF0-D0F5-4B25-A65A-A7FD3268C0F5}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>GeniusCode.Components.RelayVisitor</RootNamespace>
    <AssemblyName>gcRelayVisitor35</AssemblyName>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>

So it looks like my assembly name is indeed gcRelayVisitor35. However, since this is a nuspec package I am using for my reference, a careful look at the nuspec package shows that I am renaming the dll:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>gcRelayVisitor</id>
    <version>1.0</version>
    <title>Relay Visitor</title>
    <authors>JeremiahRedekop,Ryan D Hatch</authors>
    <owners>GeniusCode,LLC</owners>
    <projectUrl>https://github.com/GeniusCode/GeniusCode.Components.RelayVisitor</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Vistor class that allows for delegates to be assigned for simple recursive operations</description>
    <summary>Delegate based Visitor class</summary>
    <tags>visitor, delegate</tags>
  </metadata>
  <files>
    <file src="gcRelayVisitor35\bin\Release\gcRelayVisitor35.dll" target="lib\net40\gcRelayVisitor.dll" />
<file src="gcRelayVisitorSl4\bin\Release\gcRelayVisitorSl4.dll" target="lib\sl40\gcRelayVisitor.dll" />
  </files>
</package>

So it seems that the filename needs to match the assembly name. Once I fix this, I should be set to go :)

Data Access: What is Dependency Inversion good for?

After some good Pluralsight learning, I’ve been pondering the value of Dependency Inversion.  I’ve always understood the practice of organizing code and maintaining a convention, but now have a cleaner picture.

Higher level items should not have a dependency on lower level items.

I am going to use asp.net mvc in an upcoming application, so will use it as an example.

My controller needs to access some kind of data store, where is my DAL magic going to reside?  We use LLBLGen for SQL access, but I am not going to have a reference to LLBLGen dlls in my mvc application.  I am not going to be making calls to the database from my controller.  I am not even going to reference directly the dll that will be making those calls.

This is not crazy, or wasting time.  Instead of just using the IRepository interface, I will be making interfaces for each “datamanager” type that I will need.  Those interfaces will expose methods beyond a simple IQueryable<T> property that can be mocked in debug mode, or implemented at runtime.

The main benefit is that once the dependency has been inverted in this way,  the MVC Controller has been cleanly isolated from the llblgen (or EF, NHibernate, etc) datamanager.

The goal here is NOT that we would allow multiple implementations of the datamanger interface to switch ORMs (although we could). Instead, the goal is to allow mocking at runtime, and updating of the datamanager libraries without having to recompile the whole application.

I’m hoping to tidy & publish some of the libraries we’re using internally.

Abstracting IOC Containers – Part 3 : ViewModelLocator Intro

When acquiring an instance of the viewmodel, the locator should consider different sources and options.

Here is our default list of InstanceProviders we’ll use. The arguement passed into the method could be a MEF provider, or any other IOC. Because most IOCs don’t work at design time, we only add them in if we’re in runtime mode.

        protected  List<IInstanceProvider<T>> GetDefaultSources(IInstanceProvider<T> locateProviderToUse)
        {
            var list = new List<IInstanceProvider<T>>();

            var myType = GetType();
            var designMode = IsInDesignMode;

            if (myType.GetSharedValueAttributeUsage())
                list.AddTypeKeyedSingletonCachingInstanceProvider();

            list.AddFactoryInstanceProvider();

            if (designMode)
                list.AddMockingInstanceProvider();
            else
            {
                if(locateProviderToUse != null)
                    list.Add(locateProviderToUse);

                if (myType.GetRuntimeMockBehavior() == RuntimeMockingBehavior.AllowAtRuntime)
                    list.AddMockingInstanceProvider();

            }

            return list;
        }

Our class will be able to use this to acquire an instance of the viewmodel, but we’ll take a look at that later.

Abstracting IOC Containers – Part 2: Simple MEF

Based upon the last post, it is now possible to abstract MULTIPLE layers of IOC. All you need is to declare a priority list.

In this post, we’re going to support locating with a MEF based provider. This is just a simple example, wheras in MVVM-land, you will want something a little heavier to databind to.

So for now, here is how our MEF implementation of an InstanceSource looks. We inherit from InstanceProviderBase which does alot of the implementation of IInstanceProvider for us.

    public class MefInstanceProvider<T, TMefContract, TMetadata, TArgs> : InstanceProviderBase<T, TArgs>
        where T : class, TMefContract
        where TMetadata : class
        where TArgs: class
    {

        private readonly CompositionContainer _Container;
        public MefInstanceProvider(CompositionContainer container)
        {
            _Container = container;
        }

        public Func<TArgs,IEnumerable<Lazy<TMefContract,TMetadata>>, Lazy<TMefContract,TMetadata>> Selector { get; set; }
        public Func<TArgs,Lazy<TMefContract,TMetadata>,bool> Predicate {get;set;}

        protected override bool Try_Perform_Acquire_With_Args<R>(out bool wasCached, TArgs args, out R result)
        {
            result = null;
            wasCached = false;

            var lazies = _Container.GetExports<TMefContract, TMetadata>();

            if (Predicate != null)
                lazies = lazies.Where(a => Predicate(args, a));

            Lazy<TMefContract, TMetadata> myLazy =
                lazies.Count() > 1 ? Selector(args, lazies) : lazies.SingleOrDefault();

            if (myLazy != null)
            {
                result = (R)myLazy.Value;
                return true;
            }

            return false;
        }
    }

Something really cool is that we have both a predicate and a selector as public properties. This means that we can inject the delegates from the outside. Here is an extension method that supports looking for a class we use for our data access:

        public static void AddMefLLBLGenManagerSource<TSessionInfo,TLinqMetadata>(
            this IList<IInstanceProvider<IEntityManager<TSessionInfo, TLinqMetadata>>> input, CompositionContainer container)
        where TSessionInfo : class
            where TLinqMetadata : class, ILinqMetaData, new()
        {
            var mp = new MefInstanceProvider<IEntityManager<TSessionInfo, TLinqMetadata>, IEntityManager, IDataManagerMetaData, EntityManagerLocateArgs>(container)
            {
                Predicate = (args, mefExport) => mefExport.Metadata.EntityTypeName == args.EntityType.Name
            };

            input.Add(mp);
        }

Because this is an extension method, we can easy take a list of providers, and add support to find a mef export of IEntityManager using IDataManagerMetaData. The key is the predicate assignment, because it is here that we say that when the arguement object comes in, we are going to use it to find the correct export for the EntityType.

Now let’s use it. I have a LLBLGen data manager that knows how to do stuff for the CustomerEntity.

Here is the declaration. We are using a custom attribute to export this using mef:

    [ExportDataManager(typeof(CustomerEntity))]
    public class CustomerManager : SessionPlaceHolder.EntityManager<CustomerEntity>
    {

And then we can create a list of InstanceProviders, and add our mef manager source, by calling AddMefLLBLGenManagerSource() passing in a mef container.

[/csharp]
    [TestClass]
    public class SimpleLocate
    {
        private static CompositionContainer container;

        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            container = new CompositionContainer(new TypeCatalog(typeof(CustomerManager)));
        }

        [TestMethod]
        public void SimpleResolve()
        {
            var list = new List<IInstanceProvider<IEntityManager<Session,LinqMetaData>>>();
            list.AddMefLLBLGenManagerSource(container);

            var result = list.TryAcquireFromEnumerable(new EntityManagerLocateArgs() { EntityType = typeof(CustomerEntity) });
            Assert.IsTrue(result.ResultSuccessful);

            Assert.IsTrue(result.Result is CustomerManager);
        }
1

The end result is that we have a list of instance providers that is able to acquire an instance of an EntityManager, using MEF. So why all this extra work of having a list of InstanceProviders? Each case is different, and this approach allows you to not only abstract away your IOC container, but multiple IOC containers or behaviors (factory, mock, cache), as the previous post indicates.

Abstracting IOC Containers (or anything!)

  • We’re working on a concept to abstract away not just IOC containers, but any source.

Basically, you have a list of Instance providers, which look like this:

    public interface IInstanceProvider<T>
        where T : class
    {
        IAcquireResult<T, R> PerformAcquire<R>(object args = null) where R : class, T;
    }

    public interface IInstanceProvider<T, TArgs> : IInstanceProvider<T>
        where T : class
        where TArgs : class
    {
        IAcquireResult<T, R> PerformAcquire<R>(TArgs args) where R : class, T;
    }

We already implemented the following providers:

  • Factory (default constructor)
  • Cache
  • Mock
  • Locate

The locating part is quite abstract – you could use any IOC you want. We coded up a mef test but it was not as clean to read, wheras this test does a good job:

        [TestMethod]
        public void Should_Perform_AutoCache()
        {
            var list = new List<IInstanceProvider<IPerson>>();
            list.AddInstanceCachingInstanceProvider();
            list.AddFactoryInstanceProvider();
            list.AddMockingInstanceProvider();

            // factory
            Person p;
            var result1 = list.TryAcquireFromEnumerableDerived(out p);

            // cache
            Person p2;
            var result2 = list.TryAcquireFromEnumerableDerived(out p2);
            Assert.AreSame(p,p2);

            // mock (NOT LOCATE!!)
            IPerson p3;
            list.TryAcquireFromEnumerableDerived(out p3);
            Assert.AreEqual("Ryan", p3.Name);

            // cache
            IPerson p4;
            list.TryAcquireFromEnumerableDerived(out p4);
            Assert.AreSame(p3,p4);
        }

As you can see, our cache is able to store results so that instances are shared, not recreated. Of course this all depends on the order of the providers in the list, so you only have to add what you want.

The support classes for our tests look like this:

         public interface IPerson
        {
             [DefaultValue("Ryan")]
            string Name { get; set; }
            int Age { get; set; }
        }

        public class Person : IPerson
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

My favorite Visual Studio Color Scheme

I thought I would share my favorite VS setup for fonts and colors.

Here is how it looks:

In addition to downloading my settings file, you’ll also need to download the font “Envy Code R”, which is available here: http://damieng.com/blog/2008/05/26/envy-code-r-preview-7-coding-font-released

MEF Export + BinaryFormatter.Deserialize() = FAIL

Update: It seems that NetDataContractSerializer also suffers the same flaw, while DataContractSerializer works great.  I suppose this is why DataContractSerializer is used for client/server in wcf.  It seems that these limitations on the other serializers are being exposedby MEF’s push to compose apps on the fly, instead of traditional static fashion.

My friend Ryan is working on a report application that is going to use datasources packaged up by MEF.

Unfortunately, MEF & BinaryFormatter do not play well together. Somehow, BinaryFormatter does not “know” about assemblies that have been discovered by MEF.

Here is my simple MEF Contract:

    public interface ISampleMefObject
    {
        object GetObject();
    }

And here is my export:

    [Export(typeof(ISampleMefObject))]
    public class Class1 : ISampleMefObject
    {
        public object GetObject()
        {

            var q = new BinaryFormatter().Deserialize(
                new FileStream(@"C:\Users\JeremiahRedekop\Documents\Visual Studio 2010\Projects\MefTests\MefTests.Serializer\Fun.bak",
                    FileMode.Open));

            return q;
        }
    }

The “fun.bak” file is created using this simple console app:

    class Program
    {
        static void Main(string[] args)
        {
            var entity = new CustomerEntity()
            {
                CustomerId = "CHOPS"
            };

            var c = new BinaryFormatter();
            c.Serialize(new FileStream(args[0], System.IO.FileMode.Create), entity);
        }
    }

So anyway, when the code in GetObject() method fires, guess what – the BinaryFormatter has no clue about the dlls that MEF has discovered, and we get this:

System.Runtime.Serialization.SerializationException was unhandled
Message=Unable to find assembly ‘Northwind.DAL, Version=1.0.4095.18490, Culture=neutral, PublicKeyToken=null’.
Source=mscorlib
StackTrace:
at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
at MefTests.Module.Class1.GetObject() in C:\Users\JeremiahRedekop\Documents\Visual Studio 2010\Projects\MefTests\MefTests.Module\Class1.cs:line 15
at MefTests.Client.Form1.SetExportToPropertyGrid() in C:\Users\JeremiahRedekop\Documents\Visual Studio 2010\Projects\MefTests\MefTests.Client\Form1.cs:line 41
:

Just to show what the project structure is:

Fun with Windows Azure at AzureFest

Today we had an event sponsored by Vanslug called AzureFest.

There are a highlights:

  • can’t change instance size
  • brand new fancy silverlight ui

 

Here is what it looks like to create a new hosted service:

Things happening:

 

And here is the output:

Just don’t forget to stop & delete the service, and drop the database & db server.  Whew – no charges!

Authorization in Lightswitch: a summary

Lightswitch is a very exciting framework for line-of-business applications.  Most business problems are relatively simple, and can be solved with Lightswitch.

In the case for complex business problems, you are better off starting from scratch, but Lightswitch will give your clients a more affordable solution, as you finish the project much faster.

Beth Massi is a Project Manager for Visual at Microsoft, and she has a great video introducing authentication & authorization  in Lightswitch.  I grabbed a few screenshots which I think provide some good highlights.

Step 1: Create Permissions

In order to assign permissions to roles and users, you first need to create the permissions on Access Control tab on the property page for the application.

Step 2: Check for permissions in code

Lightswitch does not assign permissions in the ui, you actually have to write code.  There are 2 levels for authorization: Screens & Entities.  Screen authorization will occur at the client level, while entity authorization will occur on the server.  In other words, you will definately want to perform authorization on your entities, but to help your clients, you will also want to perform authorization checks on the client to.  If you only check on the server, you will get an error message like this:

Authorization Screens (Client)

You’ll need to access the code to accomplish this, but Lightswitch makes it easy by giving you hyperlink to click on to create and assign the correct method:

Then, you can write a method that will calculate whether or not the screen can run:

Authorization Entity (Server)

Authorizing entities is much like screens, except that we can authorize for delete, insert, read, update, and execute.  These options are available again from the ui of Visual Studio.

The code is almost identical, except that the path to the user object is slightly different:

3: Wire up Roles & Permissions at runtime

The interesting part of roles & permissions is that you link them in the database at runtime after you deploy.  In the video, Beth goes into detail on this, but here is a shot of the link:

I think the reason for not hard-coding your roles & permissions together is for cases when one applicaiton might be shared among seperate clients.  This approach gives alot of flexibility.  And if you want to re-use your role & permissions setups, they can easily be created in a stored procedure or something.

Thanks a lot for stopping by, hopefully this summary has been helpful!  Thanks to Beth & the Lightswitch team for such an exciting product!

Links: