Prism - Silverlight WCF RIA Services - Authentication

Topics: Prism v2 - Silverlight 3
Dec 16, 2009 at 4:31 PM

Has anyone tried implementing FormsAuthentication in using WCF RIA Services (using WCF RIA Services Class Library pattern) and Prism?

I could really use an example/code snippets. I understand the part where I register the WebContext with the UnityContainer. But am not sure, where to place the WebContext class, should it be in my Infrastructure class library or should it be my authentication module. How do I add the WebContext to the application resources if I am registering the service in a module called upon by the Bootstrapper. Also, I am used to adding the AuthenticationDomainContext to application lifetime objects in the XAML of App.xaml file. How do I do that in Prism if I am not referencing the WCF RIA services through the shell?

I have at one point of time been able to perform each task in different test applications but I am not able to bring them together using Prism's. Before Prism, to use Authentication I had to reference my Client side of the RIA services library and create a WebContext class manually in my main application project and it worked. I am using David Hill's sample along with the p&p's RI implementation along with some videos of MTaulty and Erik Mork but they do not have any info regarding Authentication using RIA Services in Prism as of now.

Please help. Any info or direction or sample code will be great.

Thanks a ton.

Dec 16, 2009 at 7:42 PM

It came down to this, I added a reference of the WCF Class library to the Shell (which I was trying to avoid) and loaded the Web Context and associated with Authentication Domain Context in the Init method of the App.xaml.cs and added to resources before the call to bootstrapper. If anyone has a better approach please let me know.

Mar 10, 2010 at 10:31 AM
Edited Mar 10, 2010 at 10:32 AM

The lack of guidance for implementing authentication in Prism is my main reason for avoiding Prism. It's a pity, but for us, better a working solution (Business templates MVVM) than a non-working one (Prism with people's suggestions on how to interface with the Authentication service). I'd rather someone tell me the correct place to put the code - it is infrastructure after all. It shouldn't need to be this hard.

Mar 11, 2010 at 1:23 AM
Edited Mar 11, 2010 at 2:05 PM

Here is a quick overview (with some code) of what I am doing.

I am using RIA services class library which has two pieces one is the .Web project and the other project which you will reference in the client side.

In your .Web project create you DataClasses (eg: Linq2SQL). Create your AuthenticationDomainService similar to the one below:

-----------------------------------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.DomainServices;
using System.Web.Ria;
using System.Web.Ria.ApplicationServices;
using System.Web.Ria.Data;
using System.Web.DomainServices.Providers;
using System.Web.Security;
using WCF_RIA_CL.Web.DataClasses;

namespace WCF_RIA_CL.Web.DomainServices
{
    [EnableClientAccess]
    public class AuthenticationDomainService : LinqToSqlDomainService<MyDataClassesDataContext>, IAuthentication<User>
    {
        //public override void Initialize(DomainServiceContext context)
        //{
        //    base.Initialize(context);
        //    this.DataContext.Connection.ConnectionString = ClientConnectionString.GetConnectionString();
        //} // if you want to override

        private static User DefaultUser = new User()
        {
            EntityPid = -1,
            Name = string.Empty,
            Roles = null,
            Password = string.Empty,
            UpdatedOn = DateTime.MinValue,
            IsLocked = false,
            NickName = string.Empty,
        };

        // To enable Forms/Windows Authentication for the Web Application, 
        // edit the appropriate section of web.config file.
        #region IAuthentication<User> Members

        public User GetUser()
        {
            if ((this.ServiceContext != null) &&
                (this.ServiceContext.User != null) &&
                this.ServiceContext.User.Identity.IsAuthenticated)
            {
                return this.GetUser(this.ServiceContext.User.Identity.Name);
            }
            return AuthenticationDomainService.DefaultUser;
        }

        public User Login(string userName, string password, bool isPersistent, string customData)
        {
            //throw new NotImplementedException();
            if (this.ValidateUser(userName, password))
            {
                User temp = new User();
                temp.Name = userName;
                temp.LocationCode = 1;
                temp.Roles = null;
                FormsAuthentication.SetAuthCookie(userName, isPersistent);
                
                return temp;
            }

            return null;
        }

        private bool ValidateUser(string userName, string password)
        {
            //using (var context = new MyDataClassesDataContext())
            //{
            //    var login = from l in context.login_infos
            //                where l.user_id == userName
            //                && l.password == password
            //                select l;

            //    if (login.Count() == 1)
            //        return true;

            //    return false;
            //}

            return true; // for testing always return true
        }

        public User Logout()
        {
            FormsAuthentication.SignOut();
            return AuthenticationDomainService.DefaultUser;
        }

        public void UpdateUser(User user)
        {
            //throw new NotImplementedException();
        }

        #endregion

        private User GetUser(string userName)
        {
            User user = new User();
            login_info li = this.DataContext.login_infos.First(u => u.user_id == userName);

            user.Name = li.user_id;
            user.NickName = li.nick_name;
            user.IsLocked = li.lock_ind;

            return user;
        }
    }
}
-----------------------------------------------------------------------------------------------------------------------------------------------
Compile.

I have an Infrastructure project in which I create a new class and name it WebContext (Keep the namespace simple e.g. namespace Infrastructure)
Here is the WebContext:
-----------------------------------------------------------------------------------------------------------------------------------------------
namespace Infrastructure
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web.Ria.Data;
    using System.Windows.Ria;
    using System.Windows.Ria.Services;
    using System.Windows.Ria.ApplicationServices;
    using WCF_RIA_CL.Web;

    /// <summary>
    /// Context for the RIA application.
    /// </summary>
    /// <remarks>
    /// This context extends the base to make application services and types available
    /// for consumption from code and xaml.
    /// </remarks>
    public sealed partial class WebContext : WebContextBase
    {

        #region Extensibility Method Definitions

        /// <summary>
        /// This method is invoked from the constructor once initialization is complete and
        /// can be used for further object setup.
        /// </summary>
        partial void OnCreated();

        #endregion


        /// <summary>
        /// Initializes a new instance of the WebContext class.
        /// </summary>
        public WebContext()
        {
            this.OnCreated();
        }

        /// <summary>
        /// Gets the context that is registered as a lifetime object with the current application.
        /// </summary>
        /// <exception cref="InvalidOperationException"> is thrown if there is no current application,
        /// no contexts have been added, or more than one context has been added.
        /// </exception>
        /// <seealso cref="Application.ApplicationLifetimeObjects"/>
        public new static WebContext Current
        {
            get
            {
                return ((WebContext)(WebContextBase.Current));
            }
        }

        /// <summary>
        /// Gets a user representing the authenticated identity.
        /// </summary>
        public new User User
        {
            get
            {
                return ((User)(base.User));
            }
        }
    }
}
-----------------------------------------------------------------------------------------------------------------------------------------------
In you App.xaml add the below lines (modify as required)
----------------------------------------------------------------------------------------------------------------------------------------------
xmlns:appsvc="clr-namespace:System.Windows.Ria.ApplicationServices;assembly=System.Windows.Ria"
xmlns:infrastructure="clr-namespace:Infrastructure;assembly=Infrastructure"
xmlns:authenticationDomainContext="clr-namespace:WCF_RIA_CL.Web.DomainServices;assembly=WCF_RIA_CL"

<Application.ApplicationLifetimeObjects>
        <infrastructure:WebContext>
            <infrastructure:WebContext.Authentication>
                <appsvc:FormsAuthentication>
                    <appsvc:FormsAuthentication.DomainContext>
                   <authenticationDomainContext:AuthenticationDomainContext/>
                    </appsvc:FormsAuthentication.DomainContext>
                </appsvc:FormsAuthentication>
            </infrastructure:WebContext.Authentication>
        </infrastructure:WebContext>
</Application.ApplicationLifetimeObjects>
--------------------------------------------------------------------------------------------------------------------------------
eneric;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web.Ria.Data;
    using System.Windows.Ria;
    using System.Windows.Ria.Services;
    using System.Windows.Ria.ApplicationServices;

    using WCF_RIA_CL.Web;


    /// <summary>
    /// Context for the RIA application.
    /// </summary>
    /// <remarks>
    /// This context extends the base to make application services and types available
    /// for consumption from code and xaml.
    /// </remarks>
    public sealed partial class WebContext : WebContextBase
    {

        #region Extensibility Method Definitions

        /// <summary>
        /// This method is invoked from the constructor once initialization is complete and
        /// can be used for further object setup.
        /// </summary>
        partial void OnCreated();

        #endregion


        /// <summary>
        /// Initializes a new instance of the WebContext class.
        /// </summary>
        public WebContext()
        {
            this.OnCreated();
        }

        /// <summary>
        /// Gets the context that is registered as a lifetime object with the current application.
        /// </summary>
        /// <exception cref="InvalidOperationException"> is thrown if there is no current application,
        /// no contexts have been added, or more than one context has been added.
        /// </exception>
        /// <seealso cref="Application.ApplicationLifetimeObjects"/>
        public new static WebContext Current
        {
            get
            {
                return ((WebContext)(WebContextBase.Current));
            }
        }

        /// <summary>
        /// Gets a user representing the authenticated identity.
        /// </summary>
        public new User User
        {
            get
            {
                return ((User)(base.User));
            }
        }
    }
}
Jun 27, 2011 at 12:14 AM

Hello Aditya Voleti,

I like your approahc and would like to know how do your reference the authonticationdomainservice & webcontext from your different modules, for example the login screen and from module VM.

Appreciate if you can add this information

Thanks & Best Regards

Waleed

Jun 29, 2011 at 11:17 PM

Waleed, The Infrastructure project has the WebContext class. Each Silverlight Application added to the project has a reference to the Infrastructure project which allows access to the WebContext. Ditto for the AuthenticationDomainContext.

Jul 2, 2011 at 10:58 AM

Hello Aditya,

Actually, your information was very helpful to me.

Insteed of having the webcontext lies in my Infrastructure project, I have it in the ria service client project, this way it will be available to all the client modules.

This link contains three important videos for "Colin Blair" showing how to structure correctly the ria service class library projects with all other modules with respect to authentication as well.

Have a look at it here :

http://www.riaservicesblog.net/Blog/post/RIA-Services-Enterprise-Business-Application-The-Movie.aspx

.Best regards

Waleed

Developer
Oct 12, 2011 at 2:58 PM

Hi,

For those concerned with this issue, you could check the following blog post, which provides guidance on how to use WCF services with Prism in Silverlight:

Using WCF services in Prism Silverlight applications

Also, you might find the following blog post by David Hill useful, as it provides insight on how to use WCF RIA Services with Prism:

Prism And .Net RIA Services

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Feb 14, 2012 at 7:06 PM

Hi,

You don't need to use WebContext class. You can create your own custom authentication service based on FormsAuthentication class.

public sealed class CustomFormsAuthentication : FormsAuthentication, IAuthenticationService
{
    public AuthenticationService()
    {
        DomainContext = new AuthenticationDomainContext();
    }
}

AuthenticationDomainContext class is auto-generated by a tool from AuthenticationDomainService. IAuthenticationService interface is required to register your service in container and it resides in infrastructure project.

public interface IAuthenticationService
{
    IPrincipal User { get; }
}

After registration you can use it to get access to authenticated user in other modules.

I hope this is helpfull for you.

(PS. Sorry for my bad English. I'm working on it :).)