Developing multiple packages in one go

Very often, it is the case that you are working on multiple packages at the same time. Keeping dependencies up-to-date in those scenarios can be a very tedious process.

One of the new features of OpenWrap 2.0 is the ability to build things from the command-line very quickly.

Let’s say that your project has the following layout:

  • MainProject
    • src
    • wraps

Let’s say that you also work on a reusable library called MyLib. The simplest thing is for you to add a reference to the code in a separate folder. I’m going to put a link in a folder within wraps called etc/MyLib. You can do that with an svn:external, a git submodule, an ntfs junction, whatever you want.

Now when you’re at the command line, building that dependency is rather simple.

o build-wrap -from wraps/etc/MyLib -quiet -incremental -debug

This instructs OpenWrap to use the project in there and build a package in your current folder. The Incremental flag (which is also new) lets the MSBuild runner build only what has changed in that project, and –debug builds the package in debug mode.

Only thing you now need is to update the library. OpenWrap has supported updating packages from the current directory since day one, so it’s as simple as doing:

o update-wrap MyLib

Now you may have a bunch of those libraries, so maybe doing a little script would make things easier. Powershell to the rescue.

ls wraps/etc | %{
  o build-wrap -from $_.FullName -quiet -incremental -debug
}
o update-wrap

This will now build any referenced project in your wraps/etc and automatically update everything. I’ve not added error detection for failed builds (you can do that easily enough by checking for o.exe returning something else than 0). What’s not in there either is to build inter-dependent packages in order in which they depend on each others. This is left as an exercise to the reader (hint, you only need to build a small dependency tree based on parsing “depends: name” in descriptors in each, get an ordered list and update sequentially each project before building it, which is easy as peas and should take a whole of 10 lines of powershell).

One of the things that I’m evaluating for future versions is to bake that feature in, so that any source code in wraps/etc/packageName would automatically be built on-demand and follow the dependency graph. If you think that would be useful to how you build your projects, let us know by joining the OpenWrap mailing list!

Ads

Extending configuration in OpenRasta 2.1

[Updated to clarify what the configuration meta-model actually is.]

The latest OpenRasta 2.1 code contains some changes that make extending the fluent API easier, and provide a supported way for you to write those extensions in a way that won’t break with OpenRasta 3.0.

OpenRasta configuration meta-model

The one thing everyone knows about OpenRasta is it’s resource-oriented fluent configuration API. What few people know is how it works behind the scene.

Whenever you configure a resource, the fluent API creates a ResourceModel instance and stores it. Once all the configurations are done, a set of objects process those registrations to initialize OpenRasta itself, such as registering types in the container, mapping URIs or creating a list of codecs.

Each of the configuration elements of OpenRasta is represented by one configuration object, and the set of all those configuration bits is what we call the configuration meta-model, and is stored in the IMetaModelRepository service.

The astute reader will have noticed that in practice this means that the use of the fluent API is optional, and indeed the astute reader would be absolutely right.

One of the things that was not easily doable in 2.0 was extending that meta-model by extending the existing fluent configuration API. Why would we want to do this? Let’s take an example that will expose the whole stack of extension points in OpenRasta and add support for authentication at the configuration level.

Understanding the new extension points

A typical 2.x era configuration for a resource contains multiple chained methods, one per thing you want to configure for a resource.

            using (OpenRastaConfiguration.Manual)  
            {  
                ResourceSpace.Has                       // IHas  
                    .ResourcesOfType<UserDocument>()    // IResource  
                    .AtUri("/public/{filename}")        // IUri  
                    .HandledBy<UserDocumentHandler>()   // IHandler  
                    .AsXmlDataContract();               // ICodec  
            }

The interfaces that you see on the right are new to 2.1 and are where the magic happens.

Let’s say we want to require authentication for any UserDocument resource. The recommended way to do this is to attach an extension method in your namespace and attach it to IResource.

To prevent intellisense from showing a lot of rubbish on those interfaces, to gain access to the extensibility points of the configuration API you need to cast the instance you get to IXxxTarget. In our example, let’s create a RequiresAuthentication method and add some metadata to that resource registration.

    public static class AuthenticationConfiguration  
    {  
        public static T RequiresAuthentication<T>(this T root) where T:IResourceDefinition  
        {  
            var target = root as IResourceTarget;  

            target.Resource.Properties["caffeineit.demos.fluentauth.enabled"] = true;  
            return root;  
        }  
    }

The IResourceTarget interface contains about everything you need to add anything you want to the configuration model: the meta-model repository, the current resource registration and its list of URIs, Handlers and Codecs.

Here we’ve added some additional data to enable authentication that we need to process from somewhere else.

Platform-wide operation interceptors

The second extension point we’ll use is the support for operation interceptors, which are small components that can interact and make decisions before your handler code gets called.

You may have seen them being used in OpenRasta on a per-method basis, usually together with an attribute that creates them, such as [RequiresAuthentication] or [RequiresRole]

Whenver a URI is matched by OpenRasta, it is associated with a resource key. This is the cornerstone of the OpenRasta model, as with a resource key we can find all handlers, URIs, codecs and anything else associated with the resource we have. We’re going to be using this to get the information we’ve added in our configuration.


    public class FluentAuthenticationInterceptor : IOperationInterceptor  
    {  
        IMetaModelRepository _configuration;  
        ICommunicationContext _env;  

        public FluentAuthenticationInterceptor(IMetaModelRepository configuration, ICommunicationContext env)  
        {  
            _configuration = configuration;  
            _env = env;  
        }  

        public bool BeforeExecute(IOperation operation)  
        {  
            var currentResource = _env.PipelineData.ResourceKey;  
            var registration = _configuration.ResourceRegistrations.FirstOrDefault(x => x.ResourceKey == currentResource);  

            object authEnabled;  
            if (registration != null &&  
                registration.Properties.TryGetValue("caffeineit.demos.fluentauth.enabled", out authEnabled) &&  
                (bool)authEnabled)  
            {  
                if (_env.User.Identity.IsAuthenticated == false)  
                {  
                    _env.OperationResult = new OperationResult.Unauthorized();  
                    return false;  
                }  
            }  
            return true;  
        }  

        public Func<IEnumerable<OutputMember>> RewriteOperation(Func<IEnumerable<OutputMember>> operationBuilder)  
        {  
            return operationBuilder;  
        }  

        public bool AfterExecute(IOperation operation, IEnumerable<OutputMember> outputMembers)  
        {  
            return true;  
        }  
    }

A few things are happening here. Of course we use dependency injection to take a dependency on the meta-model repository, where our configuration is stored, and on the ICommunicationContext, which gives us the principal of the current user, and which we need to know if someone has authenticated. On a side-note, that property is populated based on your hosting environment, so if you run on asp.net and have Forms authentication enabled, that will flow automatically with no work on your part.

We do the work in BeforeExecute so we can stop execution before any other code runs, be it other interceptors or our handler. Finally, if a user is not authenticated, we override the OperationResult for the current connection and return false, which instructs OpenRasta to stop processing anything and start writing the response back to the client.

Hooking up the interceptor

The last bit we have to do is to give the interceptor to OpenRasta, and like everything else, it is handled by the IoC container. We can register custom dependencies in a unified fashion using the fluent configuration API.

ResourceSpace.Uses.CustomDependency<  
                    IOperationInterceptor,   
                    FluentAuthenticationInterceptor>  
                    (DependencyLifetime.Transient);

Cleaning up and ready for packaging

Finally, like most plugins in OpenRasta, you should do all your configuration work as an extension on IUses, so we wrap the work that was done in the last bit into a nice extension method.

public static void FluentAuthentication(this IUses uses)  
        {  
            var target = (IFluentTarget)uses;  
            target.Repository.CustomRegistrations.Add(  
                new DependencyRegistrationModel(  
                    typeof(IOperationInterceptor),  
                    typeof(FluentAuthenticationInterceptor),  
                    DependencyLifetime.Transient)  
                );  
        }

And now our configuration looks nice and understandable.

            using (OpenRastaConfiguration.Manual)  
            {  
                ResourceSpace.Uses.FluentAuthentication();  

                ResourceSpace.Has                      
                    .ResourcesOfType<UserDocument>()   
                    .RequiresAuthentication()  
                    .AtUri("/public/{filename}")       
                    .HandledBy<UserDocumentHandler>()  
                    .AsXmlDataContract();              
            }

Conclusion

The same extension points are available for URIs, for handlers, codecs, media type definitions and any other configuration model that exists. If you hang off those interfaces, your extensions will still work for the new compact configuration API and the convention-based configuration API that will be part of OpenRasta 3.0.

Ads

Trying out OpenWrap 2.0

[Update 3: github is not pushing the changes to openwrap.org properly, I’ve updated the link to the shell in the post to point to the correct file.]

[Update 2: The problems with side-by-side of 2.0 and 1.0 seem to be mostly resolved. Do not install 2.0 in your system repository just yet, keep it in a test project, and please update OpenWrap to the newly released 1.0.1 version which solves some of those issues.]

[Update: I’ve temporarily removed the 2.0 packages from the beta server due to unforeseen 1.0.0 / 2.0 side-by-side execution due to a bug in 1.0.0. Expect a new set of packages soon.]

We’ve come a long way since the initial work started on OpenWrap 1.1 that turned into 2.0.

We now have ReSharper 6 support and a whole lot of new features, and we’re 50 open issues from being feature complete. Still, it’s time to announce a few things.

First, the shell has been updated to 2.0, and bring back the possibility of deleting your /wraps folder when something goes bad to force an update, as well as fix a bunch of bugs that existed in the 1.1 release. Go download it now.

The second thing is that test packages of OpenWrap 2.0 are available for testing, but not on the main repository. If you have OpenWrap 1.0 installed, you can upgrade a specific project to OpenWrap 2.0 by adding the beta repository.

C:\src> o add-remote beta http://wraps.openwrap.org/beta/
# OpenWrap Shell 2.0.0.8
# Copyright © naughtyProd Limited 2009-2011
# Using C:\Users\sebastien.lambla\AppData\Local\openwrap\wraps\_cache\openwrap-2.0.0.81133579\bin-net35\OpenWrap.dll (2.0.0.0)
Remote repository 'beta' added.

<font color="#444444" face="Georgia" size="3">Then you can update your project to the new test version.</font>

<font color="#444444" face="Georgia" size="3"></font>

C:\src\myProject> o update-wrap openwrap -project

If you want to install 2.0 in your system repository, and at this stage it is not recommended as those are early previews that do not guarantee that side-by-side execution will work, then any 1.0 project may fail with noun not found errors. If this is your case:

  • Change your wrap descriptor to force 1.0, so “depends: openwrap content” should be changed to “depends: openwrap = 1.0 content”

  • Force an update to 1.0.1 by doing “o update-wrap openwrap –proj –usesystem”

  • If this fails, let us know how, then simply reset your system repository to a known state using the –shellpanic flag before executing your update-wrap command.

In the next couple of weeks there will be very long blog posts about all the new features we have in there for you, but if you’ve been dying to test out the alpha releases, now you know how.

As usual, contributors are welcome, bug reports should be filled on http://github.com/openrasta/openwrap/. If you’ve not involved yourself in real open source, by the people, for the people, in the open and in all honesty, now is the time.

OpenWrap is the longest running and most open package manager on .net, come and have a look.

Ads