Use Memcached in .NET application with Linq
First of all, get the memcached, I user win32 version. http://jehiah.cz/projects/memcached-win32/ version 1.2.1
Secondly, get a client for memcached, I use this one http://memcachedproviders.codeplex.com/ version 1.2
Get the document for the client too, I start without it and I think you should read it in advance.
I will share some of my experience too.
The official documentation is a bit poor, I am going to give an introduction on the main points.
1. Memcached is a universal distributed cache.
i.e. it can run multiple instances and appears to the programmer as one cache server which is programming language independent. A really large hashtable.
2. It stores no object, you’ll have to serialze every object that you want to cache.
3. It won’t throw any exception no matter what happens.
I will focus on how to use the memcached server, not how to setup since you should be run it without a problem.
Setup the client in your application. Unarchive and add reference to all three .dll in your project.
Then configure your web.config or app.config like this, inside <configSections> tag, add the following:
<section name="cacheProvider" type="MemcachedProviders.Cache.CacheProviderSection, MemcachedProviders" allowDefinition="MachineToApplication" restartOnExternalChanges="true"/> <sectionGroup name="enyim.com"> <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/> </sectionGroup> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
This tells the application that there will be a section with tag <cacheprovider> and <log4net>. Also will have a section with tag <enyim.com> who has a child tag <memcached> inside. You can just copy and paste the above, it should work.
Then add the detail settings in <configuration> tag.
<cacheProvider defaultProvider="MemcachedCacheProvider">
<providers>
<add name="MemcachedCacheProvider" type="MemcachedProviders.Cache.MemcachedCacheProvider, MemcachedProviders"
keySuffix="_MySuffix_" defaultExpireTime="2000"/>
</providers>
</cacheProvider>
<enyim.com>
<memcached>
<servers>
<add address="192.168.1.2" port="11211" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>
</enyim.com>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}]- %message%newline" />
</layout>
</appender>
<root>
<priority value="WARN"/>
<appender-ref ref="ConsoleAppender">
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="WARN"/>
<levelMax value="FATAL"/>
</filter>
</appender-ref>
</root>
</log4net>
You can change the default expire time. Server address is the host which you run memcached and 11211 is the default port.
Caching string and serialized object should be something you already know. For simple class, just add [Serializable] to the class.
Let’s see how it works with LINQ.
To serialize LINQ object, open .dbml design view, select serialize mode to unidirectional.
Then you will need to use DataContractSerializer to actually serialize your object. For more information.
There are a few serializer, XML, binary, JSON, etc. I am using DataContractJsonSerializer since it should be faster than XML. The following code snippet serialize and cache the object array to memcached.
//create a serialize provider with specify object type
DataContractJsonSerializer serializeProvider = new DataContractJsonSerializer(typeof(myClass[]));
//a memory stream as buffer since the provider do not directly generate string
using (MemoryStream ms = new MemoryStream())
{
serializeProvider.WriteObject(ms, myClassArrayObject);
byte[] l_buffer = new byte[ms.Length];
ms.Position = 0;
//If the string is out of integer range, skip it, you can do whatever you need to handle this
if (ms.Length < int.MaxValue)
{
ms.Read(l_buffer, 0, (int)ms.Length);
string l_serialized = Encoding.Unicode.GetString(l_buffer);
//remove existing cache with the same key
DistCache.Remove("keyString");
DistCache.Add("keyString", l_serialized);
}
else
{
throw new Exception("object data large.");
}
}
Then you can check whether you succussfully cache it with telnet.
Telnet to your server and type the command ’stats’, it will then shows the status of your memcached.
curr_items is the number of items inside memcached.
There is some common practices in choosing the hash key but that is another topic.
I am using Application:Method:Parameters:Salt and then hash it with SHA256, convert it to base64.
This should be enough for testing purpose, you can come up with your own hash decision.
Then we will get the cache and deserialize it to our object.
string l_serialized = (string)DistCache.Get("keyString");
DataContractJsonSerializer serializeProvider = new DataContractJsonSerializer(typeof(myClass[]));
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(l_serialized)))
{
myClass[] members = (myClass[])serializeProvider.ReadObject(ms);
}
You can do this with your object, object array, object collection, etc.
But remember you are in a different data context if you get you data from cache.
This will need some workaround to update or delete data with Linq.
I will cover this part later in another article.
ASP.NET Membership/Role Model + Sitemap Security Trimming
The scenario is like this, I want to extend the ability of ASP Membership and role mode, also want to display content depends on user role.
So, I am going to use a SQL server to store and be able to extend. You can even implement you own provider class.
I will focus on how to setup and enable these features in this article.
We start with building tables in our database which we store our membership and role information.
Look under %WINDOWS%\Microsoft.NET\Framework\v2.0.50727\
There should be a ASPNET_REGSQL.exe, use it to create tables in your database.
ASPNET_REGSQL -S database_host -U username -P password -d database_name -A support_providers
for example : ASPNET_REGSQL -S 192.168.1.2 -U sa -P 1234 -d membershipDb -A All
And then, we need to configure the web.config to tell the web application that we are using membership and role.
Also, tell the provider where to get those information.
Setup a connection string to the database.
<connectionStrings>
<remove name="LocalSqlServer"/>
<add name="LocalSqlServer" connectionString="data source=.;Initial Catalog=MemRoleProvider;user id=sa;password=1234" providerName="System.Data.SqlClient" />
</connectionStrings>
The [remove] delete the connect string whose name is LocalSqlServer. This seems to be the default connection string name.
You may use your own connection string name and do not remove the default one.
At last, we create the provider for the application in the [system.web] section.
<membership defaultProvider="AnaSystemSqlMembershipProvider" userIsOnlineTimeWindow="15"> <providers> <clear/> <add name="AnaSystemSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider,System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalSqlServer" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10"/> </providers> </membership> <roleManager enabled="true" defaultProvider="AnaSystemSqlRoleProvider"> <providers> <add name="AnaSystemSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="LocalSqlServer" applicationName="/"/> </providers> </roleManager>
The [clear] remove all existing provider. The attributes reference can be found here.
ConnectionStringName should be the one that you previously configure. You should now able to leverage the power of ASP membership and role model.
The next step is to integrate with Security Trimming. I will use this feature to populate navigation menu depending on user role.
You have to have a sitemap in your web application, then activeate the security trimming like this.
Inside [system.web].
<siteMap enabled="true" defaultProvider="XmlSiteMapProvider"> <providers> <clear/> <add name="XmlSiteMapProvider" description="Default SiteMap provider." type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true" /> </providers> </siteMap>
[clear] is to remove existing sitemap provider. Next we have to enable the authenticatin feature.
Inside [system.web]
<authentication mode="Forms"> <forms name=".mycookie" path="/" loginUrl="Default.aspx" protection="All" timeout="90"/> </authentication>
The name attribute inside forms tag is the unique cookie name for the application.
Reference for other attribute can be found here.
The next step is to setup access rule for your directories. ASP access rule is directory base.
The root directory access rule is inside project’s web.config. Each directory will also have its
own web.config. Here is an example to give you an idea. inside [system.web]
<authorization> <allow users="admin" /> <deny users="?" /> </authorization>
This means the root directory is accessable by admin role and forbid anonymous users.
You can manage access rule with a UI, in VS2008->Project->ASP.NET administration tools->security.
The final step is to add some setting to your sitemap file, web.sitemap.
Add roles=”*” to your siteMapNode to enable security trimming base on access rules.
Here is an example.
<?xml version="1.0" encoding="utf-8" ?> <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" > <siteMapNode title="Home" description="Home" url="~/default.aspx" > <siteMapNode title="Guest Area" roles="*"> <siteMapNode url="~/Guest/Guest.aspx" title="guest only" description="" /> </siteMapNode>
<siteMapNode title="Power Area" roles="*"> <siteMapNode url="~/PowerUser/Content.aspx" title="power user" description="" /> </siteMapNode>
</siteMapNode> </siteMap>
That’s it. You can also fine tune it to access rule base on page file by that is beyond the scope of this article.
You can find a little reference about that here.
中文版在這裡
C# do not inherit parent class constructor
C# inheritance do not inherit parent class constructor.
If you want to invoke the parent constructor before doing anything in child constructor.
Define the child constructor as the following
ChildClassName(child parameter list) : base (child parameter list)
Two parameter lists do not need to be the same.
Assign Default File Sort Order in Windows!
標題: 為視窗設定檔案預設排序
This is a very good example of bad design!!
One day I find my default file sorting is messed up, and I want to restore it.
The way to do it is so complicated and hidden almost like Game Cheat Code…
這是一個很好的差勁設計例子
某日我的檔案排序亂掉了,我想回復到預設的排序
那個方法就像玩遊戲的秘技一樣難…
Right click My Computer, choose Explore.
Click on the C: Drive in the left pane.
Click on the View Menu, then choose List.
Right click in the empty whitespace area in the right pane where thefiles get listed.
Choose Arrange Icons By. Pick “Name”.
Verify files are sorted alphabetically. If not, repeat.
Press and hold the control key, then click on the “X” to close
Explorer.
在’我的電腦’按右鍵,選檔案總管
在左邊的選單欄選C:槽
按上面選單的檢視,選清單
在右邊檔案區塊空白的地方按右鍵
選排序方式->名稱
檢查一下排序是否按照名稱了,如果不是請重覆上面
按著Ctrl鍵,點”X”關掉檔案總管
The key here, is that the file open dialog box, and all other similar
controls, use the sort method saved when in “List” view.
If you do it using “Details” view, it won’t fix the dialog box sort order.
重點就是,在檔案總管裡,或者其他控制介面,要在”清單”檢視裡選擇排序方式
如果你用其他檢視方式,你所選的排序下一次又會跑掉.
Request.Params vs Request.QueryString
Request.Params will get the set of keys/values including queryString, form, cookies and server variables.
whereas Request.QueryString only get those http [GET] parameters which means more efficient.
Encoding Error When Passing Value in Url
Title: 使用URL傳參數出現亂碼
Use the following to solve the problem.
HttpUtility.UrlEncode()/UrlDecode()
And this method save you from some XSS attacks too ^_^
用下列方法就編碼可以
HttpUtility.UrlEncode()/UrlDecode()
這會同時避開某部份XSS攻擊
愛因斯坦
物理系的老闆教了我很多物理的知識,也跟我講了愛因斯坦的歷史.
他的廣義相對論,由日蝕得到證明,真是很傳奇.
還有光速不變怎樣被人造慧星實驗挑戰…
質量與能量互換的正確模型等…
偉人果然是不一樣…物理也可以很有趣…
但老闆也說明他們都很窮…
所以這個世界…凡人還是比較多
Extension is static method, beware of its namespace
If you are using extension method within same namespace, carefully choose your method names.
Because extension methods is actually treat as static methods.
So, if you have extension method isEmpty() for let’s say Guid and TextBox.
And both of them are in namespace Your.Extension. The compile will complete without a problem.
But you will encounter error at runtime since both static methods have the same name.
You can either choose another name or separate them in different namespace.
Export using ReportViewer without viewing
ReportViewer is a great control. You can make drill down report and preview the report in the webpage.
Export as Excel or Pdf file easily, etc. Great features.
But, sometimes the user may not want to preview the report, the just want to get the file.
You can probably do that with Crystal report, but ReportViewer can just do the same, there is no point to shift.
Here is how to export as a byte stream. Use the LocalReport.Render()
Warning[] warnings;
string[] streamids;
string mimeType;
string encoding;
string extension;
//export to excel, use "PDF" is you would like pdf format
byte[] l_reportBytes = rv_waterLicenseReport.LocalReport.Render("Excel", null, out mimeType, out encoding, out extension, out streamids, out warnings);
Response.ClearContent();
//setup the file name
Response.AddHeader("Content-Disposition", "attachment; filename=" + "ApplicationForm" + tb_LicenseNo.Text.Trim() + ".xls");
Response.AddHeader("Accept-Header", l_reportBytes.Length.ToString());
//define mime type
Response.ContentType = "application/vnd.ms-excel";
Response.OutputStream.Write(l_reportBytes, 0, l_reportBytes.Length);
Response.Flush();
Response.Close();
Strangely, the one page report of mine will export out as two page with the second page blank.
I will look into that later. For how to create a report, see my other post.