For those of you that don’t believe in interfaces and dependency injection, here’s one of the beautiful things about taking advantage of it.
If you haven’t read my last post, here’s a quick update of the project I’m working on. My wife has a photography business and she is wanting to update her site. Since I wanted to make it fun for me too, I decided to use all the best practices that I’ve learned thus far on an ASP.NET MVC project.
So basically, we started talking about using flickr to load her portfolio gallery and I had already coded it to load from the local machine. Since she wants to use the pics on her Facebook, her blog, and anywhere else that might be needed, we thought flickr was the way to go. Also, she really likes flickr’s upload and tagging system.
So since I was smart in the beginning thanks to all the different developers I follow, it was really simple to switch out all that code. The only thing I had to touch to switch out the entire photo repository was the structuremap code. Let’s get to the code:
Here is my IPhotoRepository interface, which is the only thing my UI knows about:
public interface IPhotoRepository
{
IList<Photo> GetHomePhotos();
IList<Photo> GetPhotosBy(string portfolio);
}
GetHomePhotos is a method that returns the photos I loop through on the homepage with jQuery. The GetPhotosBy method is the meat of the project.
Here is my initial implementation of the IPhotoRepository, which loops through a particular directory.
public class PhotoRepository : IPhotoRepository
{
private readonly IDirectorySearcher _directorysearcher;
public PhotoRepository(IDirectorySearcher directorySearcher)
{
_directorysearcher = directorySearcher;
}
public IList<Photo> GetHomePhotos()
{
return GetPhotosBy("home");
}
public IList<Photo> GetPhotosBy(string portfolio)
{
portfolio = portfolio.Replace(" ", "");
var photos = new List<Photo>();
foreach (var f in _directorysearcher.FindFilesStartingWith(portfolio))
if (!f.Name.Contains("_t"))
photos.Add(new Photo() { Name = f.Name });
return photos;
}
}
Basically the way we planned on it working was through a naming convention and the wife would’ve had to create the thumbnails as well…now we just use flickr’s.
My new implementation takes advantage of flickr.net, so the calls to flickr’s APIs are really simplified. Here is the new implementation:
public class FlickrPhotoRepository : IPhotoRepository
{
public IList<Core.Domain.Model.Photo> GetHomePhotos()
{
return GetPhotosBy("home");
}
public IList<Core.Domain.Model.Photo> GetPhotosBy(string portfolio)
{
var flickr = new Flickr("yourapikey");
var ps = flickr.PhotosSearch("yourflickruserid", portfolio, PhotoSearchExtras.OriginalFormat);
return Mapper.Map(ps.PhotoCollection, new List<Core.Domain.Model.Photo>());
}
}
There are a couple of things that are interesting about the above code. One is the PhotoSearchExtras.OriginalFormat, which returns a null for the original picture unless you upgrade to flickr pro. It took me about an hour to realize that that was the problem because it doesn’t really tell you to make sure you upgrade to pro in the error message. You just have to go read and research to figure it out.
The other interesting thing about the code above is the Mapper.Map, which is an automapper function. Here is my create map code, which resides in my automapper profile class. For more information about automapper, you can visit the automapper site or read my post on it.
Mapper.CreateMap<FlickrNet.Photo, Photo>()
.ForMember(dest => dest.ImageUrl, opt => opt.MapFrom(src => src.OriginalUrl))
.ForMember(dest => dest.ThumbnailUrl, opt => opt.MapFrom(src => src.SquareThumbnailUrl))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Title));
This is the beauty of interfaces because here is my PortfolioController:
public class PortfolioController : SmartController
{
private readonly IPhotoRepository _photorepository;
public PortfolioController(IPhotoRepository photoRepository)
{
_photorepository = photoRepository;
}
public ActionResult Index(string name)
{
var pv = new PortfolioView {Name = name, Photos = _photorepository.GetPhotosBy(name)};
return View(pv);
}
}
See it has no idea that I completely changed the implementation of the photo repository. Another cool thing to mention I think is that the wife can add how many ever different portfolios that she wants. All she needs to do is create a tag and then go to /portfolio/newtagname and her site will load that particular photo list with that tag. So if you want to go to her weddings gallery, you’d go to /portfolio/weddings, if she had a preview for a client, she could do /portfolio/lastnameofclient and just not link that on her site. Anyhow, I thought it was cool. I don’t remember where I heard this, but some developer at some point told me it’s important to create hackable URLs so your end-users can guess at the URL.
So the only code I had to change to swap out the repository was this line:
That’s it! As always, please comment if you see anywhere that I could improve or you just have a comment. Thanks for reading!