Edit on GitHub

v4.0.23 Release Notes

AutoQuery

The big ticket feature in this release is the new AutoQuery feature - with our approach of enabling Queryable Data Services, that’s designed to avoid OData’s anti-patterns and pitfalls.

AutoQuery Services are normal ServiceStack Services

AutoQuery also benefits from just being normal ServiceStack Services where you can re-use existing knowledge in implementing, customizing, introspecting and consuming ServiceStack services, i.e:

Getting Started

AutoQuery uses your Services existing OrmLite DB registration, the example below registers an InMemory Sqlite Provider:

container.Register<IDbConnectionFactory>(
    new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider));

There are no additional dependencies, enabling AutoQuery is as easy as registering the AutoQueryFeature Plugin:

Plugins.Add(new AutoQueryFeature { MaxLimit = 100 });

The configuration above limits all queries to a maximum of 100 results.

The minimum code to expose a Query Service for the Rockstar table under a user-defined Route is just:

[Route("/rockstars")]
public class FindRockstars : QueryBase<Rockstar> {}

With no additional code, this allows you to use any of the registered built-in conventions, e.g:

/rockstars?Ids=1,2,3
/rockstars?AgeOlderThan=42
/rockstars?AgeGreaterThanOrEqualTo=42
/rockstars?FirstNameIn=Jim,Kurt
/rockstars?FirstNameBetween=A,F
/rockstars?FirstNameStartsWith=Jim
/rockstars?LastNameEndsWith=son
/rockstars?IdAbove=1000

You’re also able to formalize your API by adding concrete properties to your Request DTO:

public class QueryRockstars : QueryBase<Rockstar>
{
    public int? AgeOlderThan { get; set; }
}

Which now lets you access AutoQuery Services from the ServiceStack’s Typed Service Clients:

client.Get(new QueryRockstars { AgeOlderThan = 42 });

You can also take advantage of the new GetLazy() API to transparently stream large result-sets in managable-sized chunks:

var results = client.GetLazy(new QueryMovies { Ratings = new[]{"G","PG-13"}}).ToList();

As GetLazy returns a lazy IEnumerable<T> sequence it can be used within LINQ expressions:

var top250 = client.GetLazy(new QueryMovies { Ratings = new[]{ "G", "PG-13" } })
    .Take(250)
    .ConvertTo(x => x.Title);

This is just a sampler, for a more complete guide to AutoQuery checkout the AutoQuery wiki.

New VistaDB OrmLite Provider!

Also in this release is a preview release of OrmLite’s new support for VistaDB thanks to the efforts of Ilya Lukyanov.

VistaDB is a commercial easy-to-deploy SQL Server-compatible embedded database for .NET that provides a good alternative to Sqlite for embedded scenarios.

To use first download and install VistaDB itself, then grab OrmLite’s VistaDB provider from NuGet:

PM> Install-Package ServiceStack.OrmLite.VistaDb

Then register the VistaDB Provider and the filename of what embedded database to use with:

VistaDbDialect.Provider.UseLibraryFromGac = true;

container.Register<IDbConnectionFactory>(
    new OrmLiteConnectionFactory("Data Source=db.vb5;", VistaDbDialect.Provider));

The VistaDB provider is almost a complete OrmLite provider, the one major missing feature is OrmLite’s new support for Optimistic Concurrency which is missing in VistaDB which doesn’t support normal Database triggers but we’re still researching the most optimal way to implement this in VistaDB.

Improved AspNetWindowsAuthProvider

A new LoadUserAuthFilter was added to allow AspNetWindowsAuthProvider to retrieve more detailed information about Windows Authenticated users by using the .NET’s ActiveDirectory services, e.g:

public void LoadUserAuthInfo(AuthUserSession userSession, 
    IAuthTokens tokens, Dictionary<string, string> authInfo)
{
    if (userSession == null) return;
    using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
    {
        var user = UserPrincipal.FindByIdentity(pc, userSession.UserAuthName);
        tokens.DisplayName = user.DisplayName;
        tokens.Email = user.EmailAddress;
        tokens.FirstName = user.GivenName;
        tokens.LastName = user.Surname;
        tokens.FullName = (String.IsNullOrWhiteSpace(user.MiddleName))
            ? "{0} {1}".Fmt(user.GivenName, user.Surname)
            : "{0} {1} {2}".Fmt(user.GivenName, user.MiddleName, user.Surname);
        tokens.PhoneNumber = user.VoiceTelephoneNumber;
    }
}

Then to use the above custom filter register it in AspNetWindowsAuthProvider with:

Plugins.Add(new AuthFeature(
    () => new CustomUserSession(),
    new IAuthProvider[] {
        new AspNetWindowsAuthProvider(this) {
            LoadUserAuthFilter = LoadUserAuthInfo
        }
    ));

Above example kindly provided by Kevin Howard.

Other features