カテゴリー別アーカイブ: WCF RIA Services

【Silverlight】 ログイン認証で、WCF RIA Servicesの利用制限を行うには

◆ 認証機能は、前回のログイン認証を利用

using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;

namespace Web.Services.LoginService
{
    [EnableClientAccess()]
    public class LoginTestService : DomainServiceBase
    {
        // RequiresAuthentication属性を適用した場合、
        // 認証済みユーザーのみアクセス可能となる。
        [RequiresAuthentication()]
        public IQueryable<Uma> GetUmas()
        {
            return base.GetQuery<Uma>();
        }

        // RequiresRole属性を適用した場合、
        // ロールに所属するユーザーのみアクセス可能となる。
        [RequiresRole("Administrator")]
        public void UpdateUma(Uma entity)
        {
            base.UpdateQuery<Uma>(entity);
        }
    }
}

広告

【Silverlight】 WCF RIA Servicesを使用して、ログイン認証を行うには

◆ ログイン検証 プロバイダー

using System;
using System.Web.Security;

namespace Web.Services.LoginService
{
    public class CustomMembershipProvider : MembershipProvider
    {
        // ログイン検証
        public override bool ValidateUser(string username, string password)
        {
            // 今回は、ユーザー名とパスワードが一致したら認証OKとする。
            return (username.Equals(password));                
        }

        public override MembershipUser GetUser
            (string username, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        // 今回、以下 override は同様にNotImplementedException を実装
        // ・・・
    }
}

◆ ロール設定 プロバイダー

using System;
using System.Web.Security;

namespace Web.Services.LoginService
{
    public class CustomRoleProvider : RoleProvider
    {
        // ユーザーに対するロールを設定
        public override string[] GetRolesForUser(string username)
        {
            // 今回は、ユーザー名が admin であれば管理者とする。
            if (username.Equals("admin") )
            {
                return new string[] { "Administrator" };
            }
            else
            {
                return new string[] { "Gest" };
            }
        }

        public override string[] FindUsersInRole
            (string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }
        
        // 今回、以下 override は同様にNotImplementedException を実装
        // ・・・
    }
}

◆ Web.config

<system.web>
    // ・・・省略    
    <!-- Form認証 -->
    <authentication mode="Forms" />
    <!-- プロバイダー情報 -->
    <membership defaultProvider="customProvider">
      <providers>
        <add name="customProvider" 
            type=" Web.Services.LoginService.CustomMembershipProvider" />
      </providers>
    </membership>
    <roleManager enabled="true" defaultProvider="customProvider">
      <providers>
        <add name="customProvider" 
            type=" Web.Services.LoginService.CustomRoleProvider"/>
      </providers>
    </roleManager>    
</system.web>
  

◆ ユーザー エンティティ

using System.ServiceModel.DomainServices.Server.ApplicationServices;

namespace Web.Services.LoginService
{
    public class CustomUser : UserBase
    {
        // プロパティを実装する。今回は未実装。
    }
}

◆ ログイン認証 WCF RIA Services

using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server.ApplicationServices;

namespace Web.Services.LoginService
{
    [EnableClientAccess]
    public class LoginService : AuthenticationBase<CustomUser>
    {

    }
}

◆ Silverlight

// ログイン認証 WCF RIA Services の呼び出し
var context = new LoginContext();
context.Load(context.LoginQuery(loginId, password, true, null),
    result =>
    {
        if (result.HasError)
        {
            // ログイン エラー
            IsLogin = false;
        }
        else
        {
            // ログイン ユーザーを取得
            var user = result.Entities.FirstOrDefault();
            // user が null の場合は、認証NG
            IsLogin = (user == null ? false : true);
        }                    
    }, null);
    

【Silverlight】 WCF RIA Services(DbDomainService) のCRUD基底クラスを作成するには(ジェネリック・メソッドの場合)

◆ WCF RIA Services(DbDomainService) のCRUD基底クラス

using System.Linq;
using System.Data;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using System.ServiceModel.DomainServices.EntityFramework;
using System.Data.Entity.Infrastructure;

namespace Web.Services
{
    // CRUDドメインサービス基底クラス
    public abstract class DomainServiceCrud : DbDomainService<RaceContext>
    {
        // 読取
        protected virtual IQueryable<T> GetQuery<T>()
            where T : class
        {
            return this.DbContext.Set<T>();
        }

        // 更新
        protected virtual void UpdateQuery<T>(T entity)
            where T : class
        {
            var original = this.ChangeSet.GetOriginal(entity);

            if (original != null)
            {
                this.DbContext.Set<T>().AttachAsModified<T>(
                    entity, original, this.DbContext);
            }
            else
            {
                this.DbContext.Set<T>().Attach(entity);
            }
        }

        // 生成
        protected virtual void InsertQuery<T>(T entity)
            where T : class
        {            
            DbEntityEntry<T> entityEntry = this.DbContext.Entry<T>(entity);

            if (entityEntry.State != EntityState.Detached)
            {
                entityEntry.State = EntityState.Added;
            }
            else
            {
                this.DbContext.Set<T>().Add(entity);
            }
        }

        // 削除
        protected virtual void DeleteQuery<T>(T entity)
            where T : class
        {
            DbEntityEntry<T> entityEntry = this.DbContext.Entry<T>(entity);

            if (entityEntry.State != EntityState.Deleted)
            {
                entityEntry.State = EntityState.Deleted;
            }
            else
            {
                this.DbContext.Set<T>().Attach(entity);
                this.DbContext.Set<T>().Remove(entity);
            }
        }
    }
}

◆ 使用例

using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;

namespace Web.Services
{
    [EnableClientAccess()]
    public class CrudService : DomainServiceCrud
    {
        // 読取
        [Query]
        public IQueryable<Race> GetRaces()
        {
            return base.GetQuery<Race>();
        }

        // 更新
        [Update]
        public void UpdateRace(Race entity)
        {
            base.UpdateQuery<Race>(entity);
        }

        // 生成
        [Insert]
        public void InsertRace(Race entity)
        {
            base.InsertQuery<Race>(entity);
        }

        // 削除
        [Delete]
        public void DeleteRace(Race entity)
        {
            base.DeleteQuery<Race>(entity);
        }
    }
}

【Silverlight】 WCF RIA Services(DbDomainService) のCRUD基底クラスを作成するには(ジェネリック・クラスの場合)

◆ WCF RIA Services(DbDomainService) のCRUD基底クラス

using System.Linq;
using System.Data;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using System.ServiceModel.DomainServices.EntityFramework;
using System.Data.Entity.Infrastructure;

namespace Web.Services
{
    // CRUDドメインサービス基底クラス
    public abstract class DomainServiceCrud<T> : DbDomainService<RaceContext>
        where T : class
    {
        // 読取
        protected virtual IQueryable<T> GetQuery()
        {
            return this.DbContext.Set<T>();
        }

        // 更新
        protected virtual void UpdateQuery(T entity)
        {
            var original = this.ChangeSet.GetOriginal(entity);

            if (original != null)
            {
                this.DbContext.Set<T>().AttachAsModified<T>(
                    entity, original, this.DbContext);
            }
            else
            {
                this.DbContext.Set<T>().Attach(entity);
            }
        }

        // 生成
        protected virtual void InsertQuery(T entity)
        {
            DbEntityEntry<T> entityEntry = this.DbContext.Entry<T>(entity);

            if (entityEntry.State != EntityState.Detached)
            {
                entityEntry.State = EntityState.Added;
            }
            else
            {
                this.DbContext.Set<T>().Add(entity);
            }
        }

        // 削除
        protected virtual void DeleteQuery(T entity)
        {
            DbEntityEntry<T> entityEntry = this.DbContext.Entry<T>(entity);

            if (entityEntry.State != EntityState.Deleted)
            {
                entityEntry.State = EntityState.Deleted;
            }
            else
            {
                this.DbContext.Set<T>().Attach(entity);
                this.DbContext.Set<T>().Remove(entity);
            }
        }
    }
}

◆ 使用例

using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;

namespace Web.Services
{
    [EnableClientAccess()]
    public class CrudService : DomainServiceCrud<Race>
    {
        // 読取
        [Query]
        public IQueryable<Race> GetRaces()
        {
            return base.GetQuery();
        }

        // 更新
        [Update]
        public void UpdateRace(Race entity)
        {
            base.UpdateQuery(entity);
        }

        // 生成
        [Insert]
        public void InsertRace(Race entity)
        {
            base.InsertQuery(entity);
        }

        // 削除
        [Delete]
        public void DeleteRace(Race entity)
        {
            base.DeleteQuery(entity);
        }
    }
}

【Silverlight】Entity Framework + WCF RIA Servicesで、Code First(コード・ファースト)開発を行うには

◆ 修正履歴

2011/07/11
 IISにデプロイした場合、System.ServiceModel.EndpointNotFoundException が
発生する不具合修正。(DomainService から DbDomainService クラスへ変更)

◆ 事前準備

1. Entity Framework 4.1のインストール
  ★NuGet
    http://nuget.org/List/Packages/EntityFramework
  ★インストーラー
    http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=8363
    ・Webプロジェクト側に、EntityFramework.dll を参照設定

2. RIAServices.EntityFramework のインストール
  ★NuGet
    http://nuget.org/List/Packages/RIAServices.EntityFramework
  ★インストーラー
    http://www.silverlight.net/getstarted/riaservices/
    ・Webプロジェクト側に、
      Microsoft.ServiceModel.DomainServices.EntityFramework.dll を参照設定

◆ モデル・クラス(エンティティの定義)

using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Collections.Generic;

namespace TestApplication.Web.Models
{
    // Contextクラス(DBのテーブル情報)
    public class ScheduleContext : DbContext
    {
        public DbSet<Schedule> Schedules { get; set; }
    }

    // Entityクラス(テーブルのフィールド情報)
    public class Schedule
    {
        [Key]
        public int ScheduleId { get; set; }

        public string RecordSpec { get; set; }
        public string DataKubun { get; set; }
        public int MakeDate { get; set; }

        public int Ymd { get; set; }
        public string JyoCD { get; set; }
        public int Kaiji { get; set; }
        public int Nichiji { get; set; }
        public int YoubiCD { get; set; }
    }

    /// DB生成処理クラス
    /// 【Ex】
    ///   CreateDatabaseIfNotExists<T> : DBが存在しない場合のみ生成
    ///   DropCreateDatabaseIfModelChanges<T> : モデルが変更された場合のみ再生成
    ///   DropCreateDatabaseAlways<T> : アプリケーション起動時に常にDBを再生成
    public class ScheduleInitializer
        : DropCreateDatabaseIfModelChanges<ScheduleContext>
    {
        protected override void Seed(ScheduleContext context)
        {
            // 初期レコードの作成
            var schedule = new List<Schedule>
            {
                new Schedule
                {
                    ScheduleId = 1,
                    Ymd = 20110101,
                    JyoCD = "01",
                    Kaiji = 1,
                    Nichiji=1
                }
            };

            schedule.ForEach(s => context.Schedules.Add(s));
            context.SaveChanges();
        }
    }
}

◆ Global.asax(起動時にDB生成処理を実行)

using System.Data.Entity;
using TestApplication.Web.Models;

namespace TestApplication.Web
{
    public class Global : System.Web.HttpApplication
    {
        protected void 
            Application_Start(object sender, EventArgs e)
        {
            // DBを生成
            Database.SetInitializer<ScheduleContext>
                (new ScheduleInitializer());
        }
    }
}

◆ Web.config(DB接続情報+WCF RIA Servicesの定義)

<?xml version="1.0"?>
<configuration>
  // 省略
  <!-- WCF RIA Servicesで使用-->
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="DomainServiceModule" preCondition="managedHandler" 
        type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, 
        System.ServiceModel.DomainServices.Hosting, 
        Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </modules>
    <validation validateIntegratedModeConfiguration="false" />
  </system.webServer>
  <system.web>
    <httpModules>
      <add name="DomainServiceModule" 
      type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, 
          System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, 
          Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </httpModules>
    <compilation debug="true" targetFramework="4.0">
      <assemblies>
        <add assembly="System.Data.Entity, 
        Version=4.0.0.0, 
        Culture=neutral, PublicKeyToken=b77a5c561934e089" />
      </assemblies>
    </compilation>
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" 
      multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <!-- DB接続名は、Contextクラスのと同一に設定(命名規則)-->
  <connectionStrings>    
    <add name="ScheduleContext" 
    connectionString="Data Source=|DataDirectory|MyDb.sdf" 
    providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>
  // 省略
</configuration>

◆ WCF RIA Services

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
using System.ServiceModel.DomainServices.EntityFramework;

namespace TestApplication.Web.Services
{
    using TestApplication.Web.Models;

    [EnableClientAccess()]
    public class ScheduleService : DbDomainService<ScheduleContext>
    {
        public IQueryable<Schedule> GetSchedule()
        {
            return this.DbContext.Schedules;
        }
    }
}

◆ Silverlight(C# Code)

var ctx = new ScheduleContext();

var query = from schedule in ctx.GetScheduleQuery()
            select schedule;

ctx.Load(query).Completed += (e, s) =>
{
    var scheduleList = ctx.Schedules.ToList();
};