Dashboard image/photo management

This is a set of recommendations for importing student, staff, and education organization (e.g., school, local education agency) photos into the Ed-Fi Dashboards. An architectural walkthrough of the core implementation is also provided.

Importing Photos
Photos can be uploaded through the Photo Management tab in the Administration section of the dashboard application. The photos should be in a ZIP file with subfolders called "Staff", "Students", "Schools" and "LocalEducationAgency" with their respective images in each folder. The images should be named with the unique identifier (district id's for students and staff) of the entity and the file extension (e.g., .jpg, .png).

Photo File Format and Dimensions
Files need a valid image in a format supported by the .NET framework with the preferred formats being jpg/jpeg or png. For other formats supported, see the Microsoft documentation for image formats http://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat.aspx. Images should be sized in a 3:4 ratio, which is the standard aspect ratio for yearbook photos. Logos for schools and local education agencies may need to be adjusted to fit a 3:4 layout.
Note: SharpZipLib (http://www.icsharpcode.net/opensource/sharpziplib/) was brought into the project to support the parsing of ZIP files.

Storing Photos
The default storage implementation (EdFi.Dashboards.Resources.Photo.Implementations.Storage.FilePhotoStorage) stores the photos in the file system in the location specified by the PersistedRepositoryDirectory setting in the web.config file.
This functionality can be easily modified through extensibility to store the files in the database, on a remote server, or any other storage location. Before using a specific implementation, permissions must be given to the application pool identity to write to the given location while the process serving up the files needs read access. If the files are being stored in a location where the filename will be shown to the user of the application, it is highly recommended to obscure the file name through encoding or a similar process.

Photo Hosting Options
The default hosting implementation (EdFi.Dashboards.Resources.Images.ContentProvider.StudentFileSystemBasedImageContentProvider and related classes) serves up the images from the file system, and is supported by the FilePhotoStorage implementation. To enable this implementation, the configuration-specific installer needs to be modified to use these implementations in a chain instead of the static providers (see below):
protected override void RegisterIImageContentProvider(IWindsorContainer container)
var assemblyTypes = typeof(Marker_EdFi_Dashboards_Resources).Assembly.GetTypes();

var chainTypes = (from t in assemblyTypes
let serviceType = t.GetInterface(typeof(IImageContentProvider).Name)
where serviceType != null && !t.IsAbstract && t.Name.EndsWith("FileSystemBasedImageContentProvider")
select t);

var chainRegistrar = new ChainOfResponsibilityRegistrar(container);
chainRegistrar.RegisterChainOf<IImageContentProvider, NullImageProvider>(chainTypes.ToArray(), "ImageContentProviderChain");

For ease of developer use and initial setup, the default implementation serves up photo images from file system of the Dashboard UI web server. While this is suitable for small implementations, performance analysis shows that having a separate web server for hosting images provides the best performance. This separate web server should be routed to by a separate subdomain with its own SSL certificate.
The web server should be configured to serve default images for people and education organizations if the requested image is not found. This can be accomplished in IIS with the URL Rewrite Module 2.0 Alternately nginx can be used for a lightweight web server with retry rules.
The web server should request the browser cache the image for an extended period of time to reduce the number of requests handled by the server. The cache expiration should take into account student photos only being refreshed once a school year. It is further recommend to add a load balancer in front of the image hosting web server and installing the certificate there. This will facilitate adding additional web servers if needed. The production Ed-Fi Dashboard instance should be configured to use the RemoteImageLinkProvider for the IImageLinkProvider. This provider requires a ‘RemoteImagePath’ entry in the appSettings section of the web.config for the Ed-Fi Dashboard. The value of the setting should be the base url for image hosting. For example: ‘https://images.edfidashboard.org’.

General Architecture
The sections below outline some of the major code elements that support the import and saving of the photos. Each interface provides a simple extension point.
Controller that receives the bytes of the uploaded file chunk by chunk and assembles them to create a single file for processing. This controller calls into the PhotoManagementService.
Assembles a request object with the current district Id and selected school Id with the file bytes that represent the school. This service calls into the PhotoProcessor.
The conductor that calls into all of the underlying implementations for specified processing. This calls into the IPackageReader, IIdentifierProvider, IPhotoResizer, and IPhotoStorage.

Through a chain of responsibility, this represents multiple parsers that attempt to parse the uploaded file. If parsed successfully, a collection of OriginalPhoto instances are returned.
public abstract class OriginalPhoto
public byte[] Photo { get; set; }

/// <summary>
/// Gets the uniquely identifying information about the photo.
/// </summary>
public abstract string FriendlyName { get; }

public class UniqueOriginalPhoto : OriginalPhoto
public long Id { get; set; }
public IdentifierType IdentifierType { get; set; }

public override string FriendlyName
get { return string.Format("{0} - {1}", Id, IdentifierType); }

Through another chain of responsibility, this represents multiple lookup providers that attempt to find the unique Ids for each entity that has a photo. If parsed successfully, an Identifier instance is returned.
public class Identifier
public int Id { get; set; }
public IdentifierType Type { get; set; }

public enum IdentifierType

Resizes the original photo into 3 separate sizes - list, thumbnail, and profile (for the header).
Stores each version of the photo.
Creation date: 12/30/2015 11:13 AM ()      Updated: 12/30/2015 1:15 PM ()