前回、LINQの結果を Cache オブジェクトに保存しましたが、コードを少し修正して保存先を memcached に変更してみます。

ジェネリック・クラスをそのまま memcached に保存できなかったので、XmlSerializer でシリアライズ・デシリアライズしています。そのため、public で読み書き可能なプロパティやフィールドだけが対象となっていますし、オーバヘッドも結構あります。

ということで、実際には最低でも BinaryFormatter でのシリアライズに変更しないと使えないとは思いますが・・・

今回も下記のサイトのコードを使わせていただきました。

Caching the results of LINQ queries
http://petemontgomery.wordpress.com/2008/08/07/caching-the-results-of-linq-queries/

 

 サンプルコード

public static class QueryResultCache
{
    static public Enyim.Caching.MemcachedClient mc = new Enyim.Caching.MemcachedClient();

    public static IEnumerable<T> FromMemcached<T>(this IQueryable<T> query)
    {
        return query.FromMemcached(TimeSpan.FromMinutes(1));
    }

    public static IEnumerable<T> FromMemcached<T>(this IQueryable<T> query,
        TimeSpan slidingExpiration)
    {

        var expression = Evaluator.PartialEval(
            query.Expression,
            QueryResultCache.CanBeEvaluatedLocally);

        string key = expression.ToString();

        key = key.ToMd5Fingerprint();

        Enyim.Caching.MemcachedClient mc = new Enyim.Caching.MemcachedClient();
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<T>));

        List<T> result;
        var c = mc.Get(key) as byte[];
        using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
        {
            if (c == null)
            {
                result = query.ToList();
                serializer.Serialize(stream, result);
                byte[] b = stream.ToArray();
                mc.Store(Enyim.Caching.Memcached.StoreMode.Set, key, b, slidingExpiration);

            }
            else
            {
                stream.Write(c, 0, c.Length);
                stream.Position = 0;
                result = serializer.Deserialize(stream) as List<T>;
            }

            stream.Close();
        }

        return result;
    }

	・・・・・
}

LINQの結果をCache オブジェクトに保存します。Queryからキーを自動的に生成しているため、簡単に使うことができます。詳しくは下記のサイトをご覧ください。

Caching the results of LINQ queries
http://petemontgomery.wordpress.com/2008/08/07/caching-the-results-of-linq-queries/

1.MSDNに記載されている ExpressionVisitor クラスをプロジェクトに追加します。

ExpressionVisitor
http://msdn.microsoft.com/en-us/library/bb882521.aspx

2.Caching the results of LINQ queries の Source code にある QueryResultCache クラス, Evaluator クラスをプロジェクトに追加します。

3.あとは通常のFromCacheメゾット を呼び出すだけで使用できます。

using (DataClassesDataContext db = new DataClassesDataContext())
{
	var people = from p in db.Person
		where p.IsReal == true
		select p;

		var result = people.FromCache().ToList();
}

memcached for windows(64-bit) のインストール で memcached をインストールしたので、ASP.NET から memcached を使ってみます。

今回は、公式に記載されているクライアントの1つである EnyimMemcached を使用します。

EnyimMemcached
http://github.com/enyim/EnyimMemcached

1.ダウンロードした Enyim.Caching.dll と log4net.dll を参照に追加します。

2. web.config に設定を追加します。下記の例では memcachedサーバーは「192.168.0.1」と「192.168.0.2」の2台で、ポートはデフォルト(11211)の環境となっています。

<configuration>
	<configSections>
		<sectionGroup name="enyim.com">
			<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
		</sectionGroup>
		<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />

		・・・・・
	</configSections>

	 <enyim.com>
		<memcached enablePerformanceCounters="false">
		<servers>
			<add address="192.168.0.1" port="11211" />
			<add address="192.168.0.2" port="11211" />
		</servers>
		<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
		</memcached>
	</enyim.com>
	<memcached keyTransformer="Enyim.Caching.TigerHashTransformer, Enyim.Caching">
		<servers>
			<add address="192.168.0.1" port="11211" />
			<add address="192.168.0.2" port="11211" />
		</servers>
		<socketPool minPoolSize="2" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
	</memcached>


	・・・・・
</configuration>

上記で使用可能となります。設定に問題なければ、普通にインスタンスを作成して使用することができますし、自動的に複数の memcached サーバへデータが保存されます。

using System;

public partial class enyim : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // MemcachedClientのインスタンス作成
        Enyim.Caching.MemcachedClient mc = new Enyim.Caching.MemcachedClient();

        // 文字列をキャッシュに入れる
        mc.Store(Enyim.Caching.Memcached.StoreMode.Set, "MyKey", "Hello World ", new TimeSpan(0, 3, 0));

        // キャッシュの文字列を表示
        Response.Write(mc.Get("MyKey"));

    }
}

Windows Server 2008 R2 に分散型メモリキャッシュシステム memcached をインストールします。

特に Windows Server 2008 R2 や 64bit だから違うと言う部分はないですが・・・

memcached についての詳しい説明は下記をご覧ください。

memcached - Wikipedia
http://ja.wikipedia.org/wiki/Memcached

 

memcached を Windowsサービス としてインストールし、サービスを開始

1.下記サイトから「Windows, (64-bit) zip file」して展開して、適当なフォルダ(例:C:\memcached)にコピーします。

memcached binary downloads - NorthScale Labs
http://labs.northscale.com/memcached-packages/
今回はバージョン 1.4.4 をダウンロード

2.管理者モードでコマンドプロンプトを実行、下記コマンドを実行し memcached をサービスへ登録します。

C:\memcached\memcached.exe -d install

3.下記のコマンドを実行し、登録した memcached サービスを開始します。

net start memcached

 

オプションの設定

memcached のオプションは、以下のレジストリ キーにある「ImagePath」を編集して設定できます。

KEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\memcached

オプションの各値については、「memcached -h」でご覧ください。

前回 の続きで、ASP.NET Web アプリケーションでDotNetOpenAuth を使って OpenID によるユーザ認証を行います。

今回は、RealmとReturnToUrlを設定して認証後に戻ってくるURLを変更します。

 

【OpenID入力ページ】

demo3.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="demo3.aspx.cs" Inherits="Test.demo3" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="Identifier" runat="server"></asp:TextBox>
        <asp:Button id="Login" runat="server" Text=" ログイン " EnableViewState="False" onclick="btnLogin_Click" /><br />
         <asp:Label ID="Result" runat="server" Text=""></asp:Label> 
    </div>
    </form>
</body>
</html>

 

demo3.aspx.cs

using System;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;

namespace WebTest
{
    public partial class demo3 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void btnLogin_Click(object sender, EventArgs e)
        {
            if (!this.Page.IsValid)
            {
                return;
            }

            using (OpenIdRelyingParty rp = new OpenIdRelyingParty())
            {
                try
                {
                    // 認証後のページを設定
                    Uri uri = new Uri("http://" + Request.Url.Authority + "/demo3return.aspx");

                    // Realm(領域)を設定
                    Realm realm = new Realm("http://" + Request.Url.Authority);

                    // IAuthenticationRequestを作成 
                    var req = rp.CreateRequest(Identifier.Text.Trim(), realm, uri);

                    // OpenID Provider に リダイレクト
                    req.RedirectToProvider();
                }
                catch (ProtocolException ex)
                {
                    Result.Text = "ERROR:" + ex.Message;
                }
            }
        }
    }
}

 

【認証後のページ】

demo3return.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="demo3return.aspx.cs" Inherits="Test.demo3return" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>結果だけのページ</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
            <asp:Label ID="Result" runat="server" Text=""></asp:Label> 
    </div>
    </form>
</body>
</html>

 

demo3return.aspx.cs

using System;
using DotNetOpenAuth.OpenId.RelyingParty;

namespace Test
{
    public partial class demo3return : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //OpenIdRelyingPartyを作成
            OpenIdRelyingParty rp = new OpenIdRelyingParty();

            // IAuthenticationResponseを取得 
            var res = rp.GetResponse();
            if (res != null)
            {
                if (res.Status == AuthenticationStatus.Authenticated)
                {
                    Result.Text = "認証成功";
                }
                else
                {
                    Result.Text = "認証失敗";
                }
            }
        }
    }
}

 

参考URL

OpenID
http://ja.wikipedia.org/wiki/OpenID

Yahoo OpenIDとは?
http://openid.yahoo.co.jp/

livedoor Auth OpenID
http://auth.livedoor.com/openid/

mixi OpenID
http://developer.mixi.co.jp/openid