You are here:   Blog
Register   |  Login

 

Apr 17

Written by: Michael Washington
4/17/2013 10:28 PM  RssIcon

image

(Note: Try the LIVE sample at: https://pictureuploader.lightswitchhelpwebsite.com/htmlclient/ (use your LightSwitchHelpWebsite.com user name and password for access))

This article describes a Visual Studio LightSwitch HTML Picture File Manager that uses WCF RIA Services to upload and view files on the web server. Using WCF RIA Services allows the application to provide fast performance by using thumbnails stored on the server hard drive when displaying lists, and the full original image when the user selects it. WCF RIA Services allow the code to be clear and easy to understand because it exposes entities that appear as normal tables, yet it is saving and reading pictures from the hard drive.

image

This example starts with the application created in: Full Control LightSwitch (ServerApplicationContext And Generic File Handlers And Ajax Calls) .

In this application, you can search users and picture names (see Server Side Search using the LightSwitch HTML Client for a tutorial on create search screens).

image

Users can select Edit My Account to update their profile and upload pictures.

image

On the Profile Page, only the user’s own photos are displayed. A user can click on a photo to edit its title.

A user can select Add User Picture to upload photos.

image

When a photo is uploaded, it will display in a preview.

image

Business rules allow a user to only upload 5 pictures.

The Project

image

The LightSwitch project is a normal LightSwitch HTML project with a WCF RIA Service. The WCF RIA Service saves  the images to the server hard drive and reads the images from the server hard drive.  It exposes two entities, UserPictures and BigPictures. Both entities look at the same files on the server hard drive. The reason there are two, is that BigPictures is used when we want to display the original image. UserPictures is used when we want to display the image thumbnails (this provides faster performance when viewing a list of pictures).

 

Displaying Pictures

image

If we look at the Main screen we see that UserPictures is bound to the Tile List control, and the GetBigPicture entity is in a Popup (that is opened when you click on a picture).

The WCF RIA Service has definitions for the two entities:

    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; }
    }

 

To retrieve the photos, the code below is used. Notice how it is actually getting all of its data from the Picture table (this is a normal SQL table) and simply replacing the FileImage property with the contents of the file (in this case the thumbnail image) on the hard drive:

 

        #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

 

When retrieving a single large picture, the following method is used:

 

        #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

 

Deleting Pictures

image

A user can edit their own pictures. When they do, they have an option to delete the picture (this will also delete the original picture and the image thumbnail from the server hard drive).

 

image

In the screen designer, we can see the Delete button.

The JavaScript code for the Delete button is actually quite simple and is exactly the same as would be used if we were not calling a 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;
    });
};

 

The underlying WCF RIA Service method is called:

 

        #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));
                    // Delet 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

 

 

Uploading Pictures

image

To upload pictures, we borrow code from the LightSwitch HTML Client Tutorial - Contoso Moving tutorial (you can see a walk-thru at this link). The main difference between that example and this one, is that in the Contoso example the pictures are stored in the database rather than the hard drive.

 

image

The layout for the Add Picture screen is simple. It contains the UserPicture entity with the FileImage property bound to a Custom Control.

The following code is used to render the contents of the Custom Control:

 

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

 

The underlying WCF RIA Service method is called:

 

        #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

To implement the business rule that a user can only upload 5 pictures, we open the UserPicture entity, and select the UserPictures_Inserting method.

We use the following code for the method:

 

public partial class UserPicturesDataService
{
    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;
        }       
    }
}

 

A Powerful Framework

WCF RIA Services allow us to create complex functionality and expose it as entities. This allow us to write the JavaScript layer using relatively straightforward code.

 

Special Thanks

A special thanks to Stephen Provine and Matt Evans for their valuable assistance.

Download Code

The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

(you must have Visual Studio 2012 Update 2 installed to run the code)

18 comment(s) so far...


Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Hi michael washington , i deployed the PictureUploader application . can you give login user name and password , i try the server authentication its throw the this error "Your login attempt was not successful. Please try again"

By venkadesan on   4/18/2013 7:48 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@venkadesan - When you deploy an application the Publish wizard has a screen that allows you to set the username and password.

By Michael Washington on   4/18/2013 8:56 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

when we gone a see grid like silverlight ?
or
can we use third party components like Ext.net

By alon on   4/18/2013 9:29 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@alon - I already have a Silverlight Picture File Manager: http://social.msdn.microsoft.com/Forums/en-US/lightswitch/thread/46df3adb-ee8e-42b8-9a15-c30adc68cd02/

By Michael Washington on   4/18/2013 9:29 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Hi Michael Washington

How do you configure the WCF RIA Service? (options for the creation)

By Romain SPADA on   6/7/2013 6:54 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@Romain SPADA - You can find out more on creating WCF RIA Services at this link:
http://lightswitchhelpwebsite.com/Blog/tabid/61/tagid/21/WCF-RIA-Service.aspx

By Michael Washington on   6/7/2013 7:23 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Hi Michael,

Do you have a similar example but with a one-to-many relationship ? Does your book explain how to?

By Francis on   9/6/2013 10:50 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@Francis - Sorry I have no examples :( Any WCF RIA Service example you Google on the web should work.

By Michael Washington on   9/6/2013 12:30 PM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

When I open the solution in VS.NET 2013 I get the following error:
PictureFileManager\PictureFileManager.ls3proj: The project cannot be upgraded with this version of Visual Studio. Please use Visual Studio 2012 with Update 2 or later to upgrade the project and follow the manual steps at: http://go.microsoft.com/fwlink/?LinkID=275855

Do you happen to have a 2013 version?

By Yannick on   2/20/2014 10:05 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@Yannick - Sorry no I do not have a VS 2013 version.

By Michael Washington on   2/20/2014 10:05 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Actually I found one in the download section a little lower. It is called: LightSwitch HTML Picture Manager Using WCF RIA Services

By Yannick on   2/26/2014 6:24 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Hi,

great tutorial and very much what you want to to, when handling with pictures.

What I don't understand from the tutorial and really hope you can help out:
Adding and deleting... How does the RIA Service know, which method to start here? Is that just by the naming Convention "InsertFile", "DeleteFile" and the parameter type? Or how does that work?

Kind regards
Simon

By Simon on   5/23/2014 2:41 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@Simon - Yes it is the naming convention.

By Michael Washington on   5/23/2014 3:44 AM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Could this be easily modified to Upload and view any file (excel, word, pdf , ... ) other than just photo?

By fatima on   8/18/2014 2:00 PM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@fatima - Yes but you also need to put in security so that a person cannot upload an executable file and then execute it, for example a .cshtml or .asp file. Also you need to prevent a person from uploading an alternate web.config file. It gets rather complicated so I just used pictures in my demonstration application.

By Michael Washington on   8/18/2014 2:02 PM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Thank you very much for your quick response.
putting security in place is a good point.
however other than the security, is it possible for you to show which part of the code I have to remove or modify in order to upload and view any kind of file?
I really appreciate your help.

By fatima on   8/18/2014 2:51 PM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

@fatima - Sorry I am unable to fulfil requests because my free time is used exploring new things :)

By Michael Washington on   8/18/2014 2:52 PM
Gravatar

Re: LightSwitch HTML Picture Manager Using WCF RIA Services

Sure, Thanks anyhow.

By fatima on   8/18/2014 3:21 PM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation