65.9K
CodeProject 正在变化。 阅读更多。
Home

LightSwitch HTML 图片管理器使用 WCF RIA Services

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2013年4月18日

CPOL

4分钟阅读

viewsIcon

23804

这是一个使用 WCF RIA Services 将文件上传和查看到 Web 服务器的 Visual Studio LightSwitch HTML 图片文件管理器。

image

注意: 在 https://pictureuploader.lightswitchhelpwebsite.com/htmlclient/ 尝试在线演示(请使用您的 LightSwitchHelpWebsite.com 用户名和密码进行访问)。

引言

本文介绍了一个 **Visual Studio LightSwitch HTML 图片文件管理器**,它使用 **WCF RIA Services** 将文件上传和查看到 Web 服务器。使用 **WCF RIA Services** 可以让应用程序通过在显示列表时使用服务器硬盘上存储的缩略图,并在用户选择时显示完整的原始图像,从而提供快速的性能。**WCF RIA Services** 使代码清晰易懂,因为它公开的实体看起来就像普通的表,但实际上是从硬盘保存和读取图片。

image

本示例始于在 Full Control LightSwitch (ServerApplicationContext and Generic File Handlers and Ajax Calls) 中创建的应用程序。

在此应用程序中,您可以搜索用户和图片名称(有关创建搜索屏幕的教程,请参阅 Server Side Search using the LightSwitch HTML Client)。

image

用户可以选择 **编辑我的帐户** 来更新他们的个人资料并上传图片。

image

在 **个人资料页面** 上,只显示用户的照片。用户可以单击照片来编辑其标题。

用户可以选择 **添加用户图片** 来上传照片。

image

上传照片后,它将显示在预览中。

image

业务规则允许用户只上传 5 张图片。

项目

image

LightSwitch 项目是一个普通的 **LightSwitch HTML** 项目,带有一个 **WCF RIA Service**。 **WCF RIA Service** 将图像保存到服务器硬盘并从服务器硬盘读取图像。它公开了两个实体:`UserPictures` 和 `BigPictures`。这两个实体都指向服务器硬盘上的相同文件。之所以有两个实体,是因为在我们要显示原始图像时使用 `BigPictures`。在我们要显示图像缩略图时(这在查看图片列表时提供了更快的性能)使用 `UserPictures`。

显示图片

image

如果我们查看 **主** 屏幕,我们会看到 `UserPictures` 绑定到 **磁贴列表** 控件,而 `GetBigPicture` 实体则在一个 **弹出窗口** 中(当您单击图片时打开)。

WCF RIA Service 具有这两个实体的定义。

       public class UserPicture
    {
        [Key]
        public int Id { get; set; }
        public string UserName { get; set; }
        public string PictureName { get; set; }
        public string ActualFileName { get; set; }
        public byte[] FileImage { get; set; }
    }

    public class BigPicture
    {
        [Key]
        public int Id { get; set; }
        public string ActualFileName { get; set; }
        public byte[] FileImage { get; set; }
    }   

为了检索照片,使用了以下代码。请注意,它实际上是从 `Picture` 表(这是一个普通 SQL 表)获取所有数据,然后用硬盘上的文件内容(在本例中是缩略图)替换 `FileImage` 属性。

        #region GetPictures
        [Query(IsDefault = true)]
        public IQueryable<UserPicture> GetPictures()
        {
            var colUserPictures = new List<UserPicture>();

            colUserPictures = (from Pictures in this.Context.Pictures
                               select new UserPicture
                               {
                                   Id = Pictures.Id,
                                   UserName = Pictures.UserName,
                                   PictureName = Pictures.PictureName,
                                   ActualFileName = Pictures.ActualFileName,
                               }).ToList();

            // Add the Pictures to the collection
            foreach (var Picture in colUserPictures)
            {
                try
                {
                    // Load Image thumbnail
                    string strThumbnailFile =
                        String.Format("{0}_thumb{1}",
                        Path.GetFileNameWithoutExtension(Picture.ActualFileName),
                        Path.GetExtension(Picture.ActualFileName));

                    string strPath = string.Format(@"{0}\{1}", 
                        GetFileDirectory(), strThumbnailFile);
                    FileStream sourceFile = new FileStream(strPath, FileMode.Open);
                    long FileSize;
                    FileSize = sourceFile.Length;
                    byte[] getContent = new byte[(int)FileSize];
                    sourceFile.Read(getContent, 0, (int)sourceFile.Length);
                    sourceFile.Close();

                    Picture.FileImage = getContent;
                }
                catch
                {
                    // Do nothing if image not found
                }
            }

            return colUserPictures.AsQueryable();
        }
        #endregion

检索单个大图片时,使用以下方法。

        #region GetBigPicture
        public BigPicture GetBigPicture(int? Id)
        {
            var objPicture = new BigPicture();

            if (Id != null)
            {
                objPicture = (from Pictures in this.Context.Pictures
                              where Pictures.Id == Id
                              select new BigPicture
                              {
                                  Id = Pictures.Id,
                                  ActualFileName = Pictures.ActualFileName,
                              }).FirstOrDefault();

                // Add the Pictures to the collection
                if (objPicture != null)
                {
                    try
                    {
                        string strPath = string.Format(@"{0}\{1}", 
                            GetFileDirectory(), objPicture.ActualFileName);
                        FileStream sourceFile = new FileStream(strPath, FileMode.Open);
                        long FileSize;
                        FileSize = sourceFile.Length;
                        byte[] getContent = new byte[(int)FileSize];
                        sourceFile.Read(getContent, 0, (int)sourceFile.Length);
                        sourceFile.Close();

                        objPicture.FileImage = getContent;
                    }
                    catch
                    {
                        // Do nothing if image not found
                    }
                }
            }

            return objPicture;
        }
        #endregion

删除图片

image

用户可以编辑自己的图片。当他们这样做时,他们可以选择 **删除** 图片(这将同时删除服务器硬盘上的原始图片和图像缩略图)。

image

在屏幕设计器中,我们可以看到 **删除** 按钮。

**删除** 按钮的 **JavaScript** 代码实际上非常简单,与不调用 **WCF RIA Service** 时使用的代码完全相同。

	myapp.EditPicture.Delete_execute = function (screen) {
	    // Delete the current picture record
	    screen.UserPicture.deleteEntity();
	    // Save the changes
	    return myapp.commitChanges().then(null, function fail(e) {
	        // There was an error -- cancel changes
	        myapp.cancelChanges();
	        // Throw the error so it will display 
	        // to the user
	        throw e;
	    });
	};

调用了底层的 **WCF RIA Service** 方法。

        #region DeleteFile
        public void DeleteFile(UserPicture objFileRecord)
        {
            string strCurrentUserName = GetCurrentUserName();
            // This picture must belong to the person deleting it
            if (strCurrentUserName == objFileRecord.UserName)
            {
                // Delete file 
                try
                {
                    string strFileDirectory = GetFileDirectory();
                    string strFileName = objFileRecord.ActualFileName;

                    string strThumbnailFile =
                        String.Format(@"{0}_thumb{1}", 
                        Path.GetFileNameWithoutExtension(strFileName), 
                        Path.GetExtension(strFileName));

                    // Delete the thumbnail and the picture
                    File.Delete(Path.Combine(strFileDirectory, strThumbnailFile));
                    File.Delete(Path.Combine(strFileDirectory, objFileRecord.ActualFileName));
                }
                catch
                {
                    // Do nothing if file does not delete
                }

                // Get database picture record
                var objPicture = (from Pictures in this.Context.Pictures
                                  where Pictures.Id == objFileRecord.Id
                                  where Pictures.UserName == strCurrentUserName
                                  select Pictures).FirstOrDefault();

                if (objPicture != null)
                {
                    // Delete database picture record
                    this.Context.Pictures.DeleteObject(objPicture);
                    this.Context.SaveChanges();
                }
            }
        }
        #endregion

上传图片

image

为了上传图片,我们借用了 LightSwitch HTML Client Tutorial - Contoso Moving 教程中的代码(您可以在 此链接 处找到演练)。该示例与本示例的主要区别在于,在 **Contoso** 示例中,图片存储在数据库中,而不是硬盘上。

image

**添加图片** 屏幕的布局很简单。它包含 `UserPicture` 实体,其中 `FileImage` 属性绑定到 **自定义控件**。

使用以下代码来渲染 **自定义控件** 的内容。

	myapp.AddPicture.FileImage_render = function (element, contentItem) {
	    // Create the Image Uploader
	    createImageUploader(element, contentItem, "max-width: 300px; max-height: 300px");
	};

调用了底层的 **WCF RIA Service** 方法。

        #region InsertFile
        public void InsertFile(UserPicture objFileRecord)
        {
            // Get current user
            string strCurrentUserName = GetCurrentUserName();

            // The file name will be prepended with the userName 
            string strActualFileName = String.Format("{0}_{1}.png", 
                strCurrentUserName, DateTime.Now.Ticks.ToString());

            // Create a Picture object
            Picture objPicture = this.Context.CreateObject<Picture>();
            // Ste values
            objPicture.ActualFileName = strActualFileName;
            objPicture.PictureName = objFileRecord.PictureName;
            // User can only Insert a picture under their identity
            objPicture.UserName = strCurrentUserName;

            // Get the local directory
            string strFileDirectory = GetFileDirectory();
            EnsureDirectory(new System.IO.DirectoryInfo(strFileDirectory));

            // Set a value for the file path
            string filePath = Path.Combine(strFileDirectory, strActualFileName);

            // Convert file to stream
            using (Stream FileImageStream = 
                new MemoryStream(objFileRecord.FileImage))
            {
                FileInfo fi = new FileInfo(filePath);

                // If file exists - delete it
                if (fi.Exists)
                {
                    try
                    {
                        fi.Delete();
                    }
                    catch
                    {
                        // could not delete
                    }
                }

                using (FileStream fs = File.Create(filePath))
                {
                    // Save the file
                    SaveFile(FileImageStream, fs);
                    fs.Close();
                }

                // Make a thumbnail of the file
                MakeThumbnail(filePath);
            }

            // Update LightSwitch Database
            this.Context.Pictures.AddObject(objPicture);
            this.Context.SaveChanges(
                System.Data.Objects.SaveOptions.DetectChangesBeforeSave);

            // Set the objFileRecord.Id to the ID that was inserted
            // In the Picture table
            objFileRecord.Id = objPicture.Id;
            // Set Actual File Name
            objFileRecord.ActualFileName = strActualFileName;
        }
        #endregion

Business Rules

image

为了实现用户只能上传 5 张图片的业务规则,我们打开 `UserPicture` 实体,然后选择 `UserPictures_Inserting` 方法。

我们为该方法使用以下代码。

       partial void UserPictures_Inserting(UserPicture entity)
       {
        string strCurrentUser = this.Application.User.Identity.Name;

        // Only allow each user to insert 5 pictures
        if (this.DataWorkspace.ApplicationData.Pictures
            .Where(x => x.UserName == strCurrentUser).Count() > 4)
        {
            throw new Exception(string.Format("{0} can only add 5 pictures.", entity.UserName));
        }
        else
        {
            // The UserName is set to the person who is logged in
            entity.UserName = this.Application.User.Identity.Name;
        }       
       }   

一个强大的框架

**WCF RIA Services** 允许我们创建复杂的功能并将其公开为实体。这使我们能够使用相对简单的代码编写 JavaScript 层。

特别感谢

特别感谢 **Stephen Provine** 和 **Matt Evans** 的宝贵协助。

LightSwitch 帮助网站文章

LightSwitch 团队 HTML 和 JavaScript 文章

© . All rights reserved.