Download the project from here:
http://code.msdn.microsoft.com/vstudio/LightSwitch-HTML-Picture-821a2bbe

(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.

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).

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

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.

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

Business rules allow a user to only upload 5 pictures.
The Project

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

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 care 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();
foreach (var Picture in colUserPictures)
{
try
{
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
{
}
}
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();
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
{
}
}
}
return objPicture;
}
#endregion
Deleting Pictures

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).

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) {
screen.UserPicture.deleteEntity();
return myapp.commitChanges().then(null, function fail(e) {
myapp.cancelChanges();
throw e;
});
};
The underlying WCF RIA Service method is called:
#region DeleteFile
public void DeleteFile(UserPicture objFileRecord)
{
string strCurrentUserName = GetCurrentUserName();
if (strCurrentUserName == objFileRecord.UserName)
{
try
{
string strFileDirectory = GetFileDirectory();
string strFileName = objFileRecord.ActualFileName;
string strThumbnailFile =
String.Format(@"{0}_thumb{1}",
Path.GetFileNameWithoutExtension(strFileName),
Path.GetExtension(strFileName));
File.Delete(Path.Combine(strFileDirectory, strThumbnailFile));
File.Delete(Path.Combine(strFileDirectory, objFileRecord.ActualFileName));
}
catch
{
}
var objPicture = (from Pictures in this.Context.Pictures
where Pictures.Id == objFileRecord.Id
where Pictures.UserName == strCurrentUserName
select Pictures).FirstOrDefault();
if (objPicture != null)
{
this.Context.Pictures.DeleteObject(objPicture);
this.Context.SaveChanges();
}
}
}
#endregion
Uploading Pictures

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.

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) {
createImageUploader(element, contentItem, "max-width: 300px; max-height: 300px");
};
The underlying WCF RIA Service method is called:
#region InsertFile
public void InsertFile(UserPicture objFileRecord)
{
string strCurrentUserName = GetCurrentUserName();
string strActualFileName = String.Format("{0}_{1}.png",
strCurrentUserName, DateTime.Now.Ticks.ToString());
Picture objPicture = this.Context.CreateObject<Picture>();
objPicture.ActualFileName = strActualFileName;
objPicture.PictureName = objFileRecord.PictureName;
objPicture.UserName = strCurrentUserName;
string strFileDirectory = GetFileDirectory();
EnsureDirectory(new System.IO.DirectoryInfo(strFileDirectory));
string filePath = Path.Combine(strFileDirectory, strActualFileName);
using (Stream FileImageStream =
new MemoryStream(objFileRecord.FileImage))
{
FileInfo fi = new FileInfo(filePath);
if (fi.Exists)
{
try
{
fi.Delete();
}
catch
{
}
}
using (FileStream fs = File.Create(filePath))
{
SaveFile(FileImageStream, fs);
fs.Close();
}
MakeThumbnail(filePath);
}
this.Context.Pictures.AddObject(objPicture);
this.Context.SaveChanges(
System.Data.Objects.SaveOptions.DetectChangesBeforeSave);
objFileRecord.Id = objPicture.Id;
objFileRecord.ActualFileName = strActualFileName;
}
#endregion
Business Rules

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:
partial void UserPictures_Inserting(UserPicture entity)
{
string strCurrentUser = this.Application.User.Identity.Name;
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
{
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.
LightSwitch Help Website Articles
An End-To-End Visual Studio LightSwitch HTML5 Application
Full Control LightSwitch (ServerApplicationContext And Generic File Handlers And
Ajax Calls)
Saving Data In The Visual Studio LightSwitch HTML Client (Including Automatic
Saves)
Creating A Desktop Experience Using Wijmo Grid In LightSwitch HTML Client
Creating ASP.NET Web Forms CRUD Pages Using ServerApplicationContext
Using Promises In Visual Studio LightSwitch
Retrieving The Current User In The LightSwitch HTML Client
Writing JavaScript That Implements The Binding Pattern In Visual Studio
LightSwitch
Implementing The Wijmo Radial Gauge In The LightSwitch HTML Client
Writing JavaScript In LightSwitch HTML Client Preview
Creating JavaScript Using TypeScript in Visual Studio LightSwitch
Theming Your LightSwitch Website Using JQuery ThemeRoller
Using Toastr with Visual Studio LightSwitch HTML Client (Preview)
LightSwitch Team HTML and JavaScript Articles
Visualizing List Data using a Map Control
Enhancing LightSwitch Controls with jQuery Mobile
Custom Controls and Data Binding in the LightSwitch HTML Client (Joe Binder)
Creating Screens with the LightSwitch HTML Client (Joe Binder)
The LightSwitch HTML Client: An Architectural Overview (Stephen Provine)
Writing JavaScript Code in LightSwitch (Joe Binder)
New LightSwitch HTML Client APIs (Stephen Provine)
A New API for LightSwitch Server Interaction: The ServerApplicationContext
Building a LightSwitch HTML Client: eBay Daily Deals (Andy Kung)
Michael Washington is a Microsoft Silverlight MVP. He is a Silverlight developer and an ASP.NET, C#, and Visual Basic programmer.
He is a DotNetNuke Core member and has been involved with DotNetNuke for over 4 years. He is the Co-Author of Building Websites with DotNetNuke (4 and 5).
He is one of the founding members of The Open Light Group (http://openlightgroup.net).
He is the founder of http://LightSwitchHelpWebsite.com
He has a son, Zachary and resides in Los Angeles with his wife Valerie.