在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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章