What recommendations will be about usage of DataObjects.NET in enterprise level services?

I saw the sample (wcf) and it is clear how to use it in some simple solutions.

Is it a good idea to have some static (shared between service instances) Business Logic Layer for wcf services?

As i understand it will make possible to make some better concurrency checks and better cache usage instead of having a session per service method call.

asked Dec 30 '10 at 02:10

Janosh's gravatar image

Janosh
47101015

edited Jan 04 '11 at 16:02

Sergey's gravatar image

Sergey
123339


One Answer:

Is it a good idea to have some static (shared between service instances) Business Logic Layer for wcf services?

In case with DO you'll anyway get it shared, since tiers share the same code (actually, it can vary - e.g. conditionally, or with conditional compilation, but in general, there should be similar API).

So you can share some BLL code in statics, but this isn't a mandatory thing. If you consider this as a good practice (IMO, it is), you can do this.

Btw, a good alternative to static methods for purely BLL stuff are session-level services. An example of such service is shown further.

  • Pros: such types are always bound to Session; transaction boundaries are automatically set for their methods.
  • Cons: likely, you don't need them, if your purpose is to explicitly shape the result (i.e. fetch the graph of entities + DisconnectedState to send them to another tier further). Explicit transaction & Session management is more desirable in this case.

As i understand it will make possible to make some better concurrency checks and better cache usage instead of having a session per service method call.

Well, this fully depends on implementation.

Concerning cache: probably, it's better to wait for our own implementation of caching API (that's one of our high priority tasks).

P.S.:

AuthenticationService - session-level service example (but for ASP.NET MVC app.):

[Service(typeof(IAuthenticationService))]
public class AuthenticationService : SessionBound,
    IAuthenticationService
{
    private static Key guestAccountKey;

    private bool loginInfoIsDefined;
    private LoginInfo loginInfo;

    public Key GuestAccountKey {
        get {
            if (guestAccountKey==null) {
                var guestAccount = Session.Query.All<Account>().Where(a => a.Name==Account.GuestAccountName).SingleOrDefault();
                if (guestAccount!=null)
                    guestAccountKey = guestAccount.Key;
            }
            return guestAccountKey;
        }
    }

    public Account GuestAccount {
        get { return Session.Query.SingleOrDefault<Account>(guestAccountKey); }
    }

    public LoginInfo LoginInfo {
        get {
            if (!loginInfoIsDefined) {
                if (Session.IsServiceSession()) {
                    // Account @ service session must be impersonated directly
                    ImpersonateAsGuest();
                    return loginInfo;
                }

                string identityName = HttpContext.Current.User.Identity.Name;
                long accountId;
                if (!long.TryParse(identityName, out accountId)) {
                    ImpersonateAsGuest();
                    return loginInfo;
                }
                var account = Session.Query.SingleOrDefault<Account>(accountId);
                if (account.IsGuest || account.Status!=AccountStatus.Active) {
                    ImpersonateAsGuest();
                    return loginInfo;
                }

                loginInfo = new LoginInfo(account.Name, account);
                loginInfoIsDefined = true;
            }
            return loginInfo;
        }
    }

    public bool Login(string eMail, string password, out Account account, bool rememberMe = false)
    {
        account = Session.Query.All<Account>().Where(a => a.EMail==eMail).SingleOrDefault();
        if (account==null)
            return false;
        if (account.PasswordHash!=Account.HashPassword(password))
            return false;
        if (account.IsGuest || (account.Status != AccountStatus.Active))
            return false;

        if (!Session.IsServiceSession())
          FormsAuthentication.SetAuthCookie(account.Id.ToString(), rememberMe);

        ImpersonateAs(account);
        return true;
    }

    public bool LoginWithIdentity(string provider, string identity, out Account account, bool rememberMe)
    {
        account = (
            from a in Session.Query.All<Account>()
            where a.Identities.Any(i => i.Provider==provider && i.Identity==identity)
            select a
            ).SingleOrDefault();
        if (account==null)
            return false;
        if (account.IsGuest || (account.Status != AccountStatus.Active))
            return false;

        if (!Session.IsServiceSession())
          FormsAuthentication.SetAuthCookie(account.Id.ToString(), rememberMe);

        ImpersonateAs(account);
        return true;
    }

    public void ImpersonateAs(Account account)
    {
        loginInfo = new LoginInfo(account.Name, account);
        loginInfoIsDefined = true;
    }

    public void ImpersonateAsGuest()
    {
        loginInfo = new LoginInfo(Account.GuestAccountName, (Account) null);
        loginInfoIsDefined = true;
    }

    public void Logout()
    {
        if (!Session.IsServiceSession())
            FormsAuthentication.SignOut();
        ImpersonateAsGuest();
    }

    // Constructors

    [ServiceConstructor]
    public AuthenticationService(Session session) 
        : base(session)
    {
    }
}

[Serializable]
public sealed class LoginInfo
{
    [DisplayName("Имя пользователя")]
    public string Name { get; private set; }
    public Ref<Account> AccountRef { get; private set; }

    public Account Account { 
        get {
            if (AccountRef.Key != null)
                return AccountRef.Value;
            else
                return Session.Demand().Services.Demand<IAuthenticationService>().GuestAccount;
        } 
    }

    [DisplayName("Логин не выполнен")]
    public bool IsGuest {
        get { return AccountRef.Key == null; }
    }

    // Constructors

    public LoginInfo(string name, Ref<Account> accountRef)
    {
        Name = name;
        AccountRef = accountRef;
    }
}

public static class ServiceExtensions
{
    ...
    public static IAuthenticationService GetAuthenticationService(this Session session)
    {
        return session.Services.Demand<IAuthenticationService>();
    }
}

Typical usage in ASP.NET MVC application:

public abstract class LoginInfoBasedViewModel : MvcViewModelBase
{
    private LoginInfo _loginInfo;

    public LoginInfo LoginInfo {
        get {
            if (_loginInfo==null)
                _loginInfo = Session.GetAuthenticationService().LoginInfo;
            return _loginInfo;
        }
        set { _loginInfo = value; }
    }
}

answered Jan 04 '11 at 15:46

Sergey's gravatar image

Sergey
123339

Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA