在Windows Azure平臺上管理文件

今天這篇文章用來闡述如何在Windows Azure的平臺上管理應用程序文件權限,如你所知,在Azure平臺上運行的程序不建議將用戶的文件放在一臺Server上面,因爲Azure平臺通常是多個實例同時運行的,而用戶是不知道自己是在訪問那一個instance(由load balancer自動分配)相互之間如果需要訪問這些Server上的文件,必須通過internal endpoint來訪問這些文件,通常你還需要對這些文件進行同步,即一個instance上面的用戶文件更新了,你必須還要將這個更新分配給所有instance。

所以我們建議把數據放在Azure的Storage裏面(也可以是SQL Azure),利用雲存儲來解決在多個instance之間數據共享的問題,而這將會帶來一些問題,例如我們需要對某些數據進行保護而不是讓所有人都能訪問到,你可能會想到通過設置BlobContainer的權限來做到這一點,但是似乎爲每個用戶去申請一個Container似乎不是非常好,因爲每個BlobContainer可以容納100T的數據,比較浪費。所以這裏我們通過這個示例來做到這一點,這裏將會按照文件路徑的形式來處理Blob文件,同時利用HttpModulerr來處理訪問的文件。

[本示例完整源碼下載(0分)] http://download.csdn.net/detail/aa466564931/4147108

針對於有些用戶不知道如何開始運行這個程序,建議瞭解一下Azure Storage:

http://msdn.microsoft.com/en-us/library/windowsazure/ee924681.aspx

設置好你的連接字符串(連接到你的Azure賬號,或者是本地測試的Storage emulator),並且必須將Azure項目設爲啓動項。

先決條件:

下載Azure SDK 1.6,並且保證已經安裝了SQL Server express版本。

名稱爲CSAzureServeFilesFromBlobStorage, 並且選擇建立一個Web Role。這裏我們同樣會使用Table Storage來管理Blob文件,如果我們需要查詢功能,只需要訪問這個Table便可以得到Blob的一些信息:

創建一個class library來處理Table Storage:

FileEntity 實體類:

    public class FileEntity : TableServiceEntity
    {
        /// <summary>
        /// No parameters constructor
        /// </summary>
        public FileEntity()
        {
            PartitionKey = "all";
            RowKey = string.Format("{0:10}-{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid()).Replace("-", "");
        }

        /// <summary>
        /// With parameters constructor
        /// </summary>
        /// <param name="partitionKey"></param>
        public FileEntity(string partitionKey)
        {
            PartitionKey = partitionKey;
            RowKey = string.Format("{0:10}-{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid()).Replace("-", "");
        }

        public string FileName
        {
            get;
            set;
        }

        public string FileUrl
        {
            get;
            set;
        }
    }


 

Context 類

    public class FileContext : TableServiceContext
    {
        public FileContext(string baseAddress, StorageCredentials credentials)
            : base(baseAddress, credentials)
        {

        }

        /// <summary>
        /// Get all entities of table storage "files".
        /// </summary>
        public IEnumerable<FileEntity> GetEntities
        {
            get
            {
                var list = this.CreateQuery<FileEntity>("files");
                return list;
            }
        }
    }


 

DataSource 類

    public class FileDataSource
    {
        private static CloudStorageAccount account;
        private FileContext context;

        public FileDataSource()
        {
            // Create table storage client via cloud account.
            account = CloudStorageAccount.FromConfigurationSetting("StorageConnections");
            CloudTableClient client = account.CreateCloudTableClient();
            client.CreateTableIfNotExist("files");

            // Table context properties.
            context = new FileContext(account.TableEndpoint.AbsoluteUri, account.Credentials);
            context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
            context.IgnoreResourceNotFoundException = true;
            context.IgnoreMissingProperties = true;
            
        }

        /// <summary>
        /// Get all entities method.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<FileEntity> GetAllEntities()
        {
            var list = from m in this.context.GetEntities
                       select m;
            return list;
        }

        /// <summary>
        /// Get table rows by partitionKey.
        /// </summary>
        /// <param name="partitionKey"></param>
        /// <returns></returns>
        public IEnumerable<FileEntity> GetEntities(string partitionKey)
        {
            var list = from m in this.context.GetEntities
                       where m.PartitionKey == partitionKey
                       select m;
            return list;
        }

        /// <summary>
        /// Get specify entity.
        /// </summary>
        /// <param name="partitionKey"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public FileEntity GetEntitiesByName(string partitionKey, string fileName)
        {
            var list = from m in this.context.GetEntities
                       where m.PartitionKey == partitionKey && m.FileName == fileName
                       select m;
            if (list.Count() > 0)
                return list.First<FileEntity>();
            else
                return null;
        }

        /// <summary>
        /// Add an entity.
        /// </summary>
        /// <param name="entity"></param>
        public void AddFile(FileEntity entity)
        {
            this.context.AddObject("files", entity);
            this.context.SaveChanges();
        }

        /// <summary>
        /// Make a judgment to check if file is exists.
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="partitionKey"></param>
        /// <returns></returns>
        public bool FileExists(string filename, string partitionKey)
        {
            IEnumerable<FileEntity> list = from m in this.context.GetEntities
                       where m.FileName == filename && m.PartitionKey == partitionKey
                       select m;
            if (list.Count()>0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }


 

接着我們要在WebRole中創建一個HttpModuler來檢測用戶的訪問和並且將禁止的request扔到錯誤處理的頁面中去:

FileManagerModuler.cs

        public void Init(HttpApplication context)
        {           
            context.BeginRequest += new EventHandler(this.Application_BeginRequest);
        }

        /// <summary>
        /// Check file types and request it by cloud blob API.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void Application_BeginRequest(Object source,EventArgs e)
        {
            string url = HttpContext.Current.Request.Url.ToString();
            string fileName = url.Substring(url.LastIndexOf('/') + 1).ToString();
            string extensionName = string.Empty;
            if (fileName.Substring(fileName.LastIndexOf('.') + 1).ToString().Equals("aspx"))
            {
                return;
            }

            if (!fileName.Equals(string.Empty))
            {
                extensionName = fileName.Substring(fileName.LastIndexOf('.') + 1).ToString();
                if (!extensionName.Equals(string.Empty))
                {
                    string contentType = this.GetContentType(fileName);
                    if (contentType.Equals(string.Empty))
                    {
                        HttpContext.Current.Server.Transfer("NoHandler.aspx");
                    };
                    {
                        FileDataSource dataSource = new FileDataSource();
                        string paritionKey = this.GetPartitionName(extensionName);
                        if (String.IsNullOrEmpty(paritionKey))
                        {
                            HttpContext.Current.Server.Transfer("NoHandler.aspx");
                        }
                        FileEntity entity = dataSource.GetEntitiesByName(paritionKey, "Files/" + fileName);
                        if (entity != null)
                            HttpContext.Current.Response.Redirect(entity.FileUrl);
                        else
                            HttpContext.Current.Server.Transfer("NoResources.aspx");
                    }
                }
            }
        }

        /// <summary>
        /// Get file's Content-Type.
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public string GetContentType(string filename)
        {
            string res = string.Empty;

            switch (filename.Substring(filename.LastIndexOf('.') + 1).ToString().ToLower())
            {
                case "jpg":
                    res = "image/jpg";
                    break;
                case "css":
                    res = "text/css";
                    break;
            }

            return res;
        }

        /// <summary>
        /// Get file's partitionKey.
        /// </summary>
        /// <param name="extensionName"></param>
        /// <returns></returns>
        public string GetPartitionName(string extensionName)
        {
            string partitionName = string.Empty;
            switch(extensionName)
            {
                case "jpg":
                    partitionName = "image";
                    break;
                case "css":
                    partitionName = "css";
                    break;
            }
            return partitionName;
        }


 

並且把HttpModule註冊到Web.config文件中,因爲WebRole是部署到IIS7.0的,所以必須放在System.WebServer下:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" >
      <add  name="ServeFilesFromBlobStorageWebRole.FileManagerModuler" type="ServeFilesFromBlobStorageWebRole.FileManagerModuler"  />
    </modules>
  </system.webServer>


 

最後製作一個上傳的功能:

        /// <summary>
        /// Upload existing resources. ("Files" folder)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnUpload_Click(object sender, EventArgs e)
        {
            FileDataSource source = new FileDataSource();
            List<string> nameList = new List<string>() { "Files/Microsoft.jpg", "Files/MSDN.jpg", "Files/Site.css" };
            CloudBlobClient client = account.CreateCloudBlobClient();
            CloudBlobContainer container = client.GetContainerReference("container");
            container.CreateIfNotExist();
            var permission = container.GetPermissions();
            permission.PublicAccess = BlobContainerPublicAccessType.Container;
            container.SetPermissions(permission);
            bool flag = false;
            
            foreach (string name in nameList)
            {
                if (name.Substring(name.LastIndexOf('.') + 1).Equals("jpg") && File.Exists(Server.MapPath(name)))
                {
                    if (!source.FileExists(name, "image"))
                    {
                        flag = true;
                        CloudBlob blob = container.GetBlobReference(name);
                        blob.UploadFile(Server.MapPath(name));

                        FileEntity entity = new FileEntity("image");
                        entity.FileName = name;
                        entity.FileUrl = blob.Uri.ToString();
                        source.AddFile(entity);
                        lbContent.Text += String.Format("The image file {0} is uploaded successes. <br />", name);
                    }
                }
                else if (name.Substring(name.LastIndexOf('.') + 1).Equals("css") && File.Exists(Server.MapPath(name)))
                {
                    if (!source.FileExists(name, "css"))
                    {
                        flag = true;
                        CloudBlob blob = container.GetBlobReference(name);
                        blob.UploadFile(Server.MapPath(name));

                        FileEntity entity = new FileEntity("css");
                        entity.FileName = name;
                        entity.FileUrl = blob.Uri.ToString();
                        source.AddFile(entity);
                        lbContent.Text += String.Format("The css file {0} is uploaded successes. <br />", name);
                    }
                }
            }

            if (!flag)
            {
                lbContent.Text = "You had uploaded these resources";
            }
        }


 

然後大家通過以下代碼來顯示現有的文件,這裏我添加兩個不存在和無效的鏈接,以示區別:

 

        private static CloudStorageAccount account;
        public string embedString = string.Empty;
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                account = CloudStorageAccount.FromConfigurationSetting("StorageConnections");
                FileDataSource source = new FileDataSource();
                IEnumerable<FileEntity> list = source.GetAllEntities();
                StringBuilder sb = new StringBuilder();
                if (list.Count() > 0)
                {
                    sb.Append("Then please check them: <br />");
                    foreach (FileEntity entity in list)
                    {
                        sb.Append("<a href='File/");
                        sb.Append(entity.FileName);
                        sb.Append("' target='_blank'>");
                        sb.Append(entity.FileName);
                        sb.Append("</a>");
                        sb.Append("<br />");
                    }

 
                }
                sb.Append("<a href='HTMLSamoke.htm' target='_blank' >HTML resource (No available)</a><br />");
                sb.Append("<a href='HTMLSamoke.jpg' target='_blank' >HTML resource (No resources)</a>");
                embedString = sb.ToString();
            }
        }


好了 當然我們還需要創建一些錯誤頁面來顯示,這裏我就不寫這些頁面的創建了,有興趣的可以下載源碼下來看看。

謝謝

 

發佈了27 篇原創文章 · 獲贊 283 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章