Neologists of the Net Unite!
How suite it is to add a new triumvirate to your MRC extravaganza (MRC is an old acronym I just (recently) made up, which stands for Model Repository Controller (a Web API project has no "View" element - that's the clients' concern/bailiwick*)).
* For any familiar with the old TV show "Dragnet," you might imagine the client saying to the REST method, in effect, "Just the facts, ma'am" The server need not be concerned about presentation - that is the client's job. All the server provides is raw, unadulterated, plain, data. The client can then parse it, format it, gussy it up, ignore it, or whatever it wants.
For those unfamiliar with "Dragnet," remember the old adage, "Age before beauty!" At any rate, you can probably pretty much suss out what it's all about.
Now, back to our scheduled programming: You can explore that initial neologism here, which also shows you how to create the easiest-possible working Web API app with IoC and DI using Castle Windsor.
Once you've done that (you've got a Windsorized Web API app), it is easy to add on to it when/if you need another
Model/Repository/Controller triad. Here's how:
Add a Model
Right-click your project's Models folder, and select Add Class...
Name it something, such as "Peeps" (not the sickeningly sweet and fancifully-colored tooth eroder, but the cool slang
word for "people").
Give it some members, such as:
public class Peeps
{
public int Id { get; set; }
public string Name { get; set; }
public string Hometown { get; set; }
}
Add a Repository Interface
Create an interface for the Repository by right-clicking the Models folder and selecting Add > Interface
Name it "IPeepsRepository
".
Mark the interface public
and give it some reasonable methods to implement so that it looks like this:
public interface IPeepsRepository
{
int GetCount();
Peeps GetById(int ID);
IEnumerable<peeps> GetRange(int ID, int CountToFetch);
IEnumerable<peeps> GetAll();
Peeps Add(Peeps item);
}
Add a Concrete Repository Class
Again, right-click the Models folder, this time selecting Add > Class...
Name it "PeepsRepository
" (or risk the wrath of Philippe Kahn, who is an old friend of mine and a cousin of Shere Khan).
Add code so that it implements the interface (IPeepsRepository
) and then add those methods and fill them out with code and even some test data in the constructor so that it looks like this:
public class PeepsRepository : IPeepsRepository
{
private readonly List<peeps> Peeps = new List<peeps>();
public PeepsRepository()
{
Add(new Peeps
{
Id = 1, Name = "T. Russell", Hometown = "Zenia, California"
});
Add(new Peeps
{
Id = 2,
Name = "A. Rosalie Kollenborn",
Hometown = "Dug Hill, Arkansas"
});
Add(new Peeps
{
Id = 3,
Name = "Theodore P. Deck",
Hometown = "Lombardi, Illinois"
});
Add(new Peeps
{
Id = 4,
Name = "Jonathan Kelly",
Hometown = "Mokelumne Hill, California"
});
Add(new Peeps
{
Id = 5,
Name = "Trish Baugus",
Hometown = "La Contenta, California"
});
Add(new Peeps
{
Id = 6,
Name = "Cherri Flowers",
Hometown = "Sonora, California"
});
Add(new Peeps
{
Id = 7,
Name = "Kelvin Caleb Mordecai",
Hometown = "Jackson, California"
});
Add(new Peeps
{
Id = 8,
Name = "Morgan Tell Mackenzie",
Hometown = "San Andreas, California"
});
Add(new Peeps
{
Id = 9,
Name = "Kamrin Marinoff",
Hometown = "Huntington Beach, California"
});
}
public int GetCount()
{
return Peeps.Count;
}
public Peeps GetById(int ID)
{
return Peeps.FirstOrDefault(p => p.Id == ID);
}
public IEnumerable<peeps> GetRange(int ID, int CountToFetch)
{
return Peeps.Where(i => i.Id >= ID).Take(CountToFetch);
}
public IEnumerable<peeps> GetAll()
{
return Peeps;
}
public Peeps Add(Peeps item)
{
if (item == null)
{
throw new ArgumentNullException("Peeps");
}
Peeps.Add(item);
return item;
}
}
Add a Controller
Right-click on your Controllers folder (your Web API project does have a Controllers folder, doesn't it? - if not, add one, or one named "api" or whatever works for you), and select Add > Controller... > Web API 2 Controller - Empty.
Name it "PeepsController
".
Add the IoC/DI/Castle Windsor-esque repository variable and interface-arg'd constructor:
private readonly IPeepsRepository _peepsRepository;
public PeepsController(IPeepsRepository peepsRepository)
{
if (peepsRepository == null)
{
throw new ArgumentNullException
("peepsRepository popped its peeper or pepper pot");
}
_peepsRepository = peepsRepository;
}
Once you grow accustomed to this strenuous activity, you can do it without breaking -- or otherwise damaging -- a sweat
(or for you exceedingly vanishing number of programmers of the female persuasion out there, without glistening)
Never may it be said that chivalry is dead!
Now, after taking a deep breath and stretching (gapping/yawning optional), add the rest of the Controller code:
[Route("api/Peeps/Count")]
public int GetCountOfPeepsRecords()
{
return _peepsRepository.GetCount();
}
[Route("api/Peeps/GetAll")]
public IEnumerable<peeps> GetAllPeeps()
{
return _peepsRepository.GetAll();
}
[Route("api/Peeps/{ID:int}")]
public Peeps GetPeepsById(int ID)
{
return _peepsRepository.GetById(ID);
}
[Route("api/Peeps/{ID:int}/{CountToFetch:int}")]
public IEnumerable<peeps> GetRangeOfPeepsByStartingID(int ID, int CountToFetch)
{
return _peepsRepository.GetRange(ID, CountToFetch);
}
}
Recordar el Castillo de Arena
Castle Windsor is not a sand castle, but I like that Spanish phrase "Castillo de Arena"; anyway, finally, add a line of code to your Repositories Installer (if you followed along with the article referenced above, it's in your DIInstallers folder), so that that class looks like this (new entry added to the middle):
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<ispy>().ImplementedBy<spy>().LifestylePerWebRequest(),
. . .
Component.For<ipeepsrepository>().ImplementedBy<peepsrepository>().LifestylePerWebRequest(),
. . .
Component.For<iofthetyger>().ImplementedBy<ofthetyger>().LifestylePerWebRequest());
}
}
Czech It Out
Try it out for yourself; enter the appropriate URIs in your browser (such as "http://localhost:28642/api/peeps/GetAll[^]", etc.), and you will see that the expected data is returned.
See! That was easier than falling off a log file and landing in a mud pile (and almost as much fun).