This is the fourth post in a series of writing a SharePoint Service Application. As stated in part 3, if you’ve missed the first posts, read those or this won’t make a lick of sense. (It may not make a lick of sense regardless!) Once again, note that creating a service application is OVERKILL for most things you’ll create for SharePoint. And while this example only spits out a simple “Hello World” type of sample, you can use this as “starter code” for a much more complex application.
For those who attended SharePoint Saturday in Denver last week, here’s the promised code, and thanks for coming to my session!
Here are the first four posts in this series:
Now that you have the guts in place, it’s time to create the deployment solution. Whenever you write complex SharePoint solutions, it’s best to keep the SharePoint project that creates the WSP file scoped to the deployment. Think of it ONLY as the Installer project for your SharePoint solution.
Since it’s been a while since I wrote the first posts (I am sorry if you’ve been waiting…), I am going to take the lazy approach here, and post the code for you to download and follow along. Rather than trying to walk you through creating it from scratch, simply download the source and I’ll talk you through the components.
DOWNLOAD THE SERVICE APPLICATION SOURCE HERE
In the source code you’ll see 2 project: the first is the SuperCoolServiceLibrary. This is the code for the service application, as discussed in the previous posts. The second is the SharePoint “installer” project which we’ll focus on in this post.
The WSP needs to contain the following mapped folder structure:
- ADMIN (mapped folder {SharePointRoot}\Template\ADMIN)
- SuperCoolServiceApplication
- Default.aspx
- Manage.aspx
- SuperCoolServiceApplication
- Layouts (mapped folder {SharePointRoot}\Template\Layouts)
- SuperCoolServiceApplication
- Debug.aspx (just a test page)
- SuperCoolServiceApplication
- WebClients (mapped folder {SharePointRoot}\WebClients)
- SuperCoolServiceApplication
- Client.config
- SuperCoolServiceApplication
- WebServices (mapped folder {SharePointRoot}\WebServices)
- SuperCoolServiceApplication
- Web.config
- SuperCool.svc
- SuperCoolServiceApplication
Let’s start with the most obvious. WebServices contains the WCF web service which will be the backend WCF service. Note that it needs a Web.config file as well as the .svc file.
Next up is WebClients. WebClients contains the client.config file which the configuration based channel factory will use to communicate to the backend service.
Then… the Layouts folder contains just a debug page which will exercise the Hello World method in the service.
Most importantly, you’ll need to include an installer feature which will create the instances and make available your service in the Manage Application Services page. That code looks like this (from installer.eventreceiver.cs):
public override void FeatureActivated(SPFeatureReceiverProperties properties) { SPFarm farm = SPFarm.Local; SPServer server = SPServer.Local; // check if the service has already been installed in the farm var service = farm.Services.GetValue<SuperCoolService>(); if (service == null) { // create the service service = new SuperCoolService(farm); service.Status = SPObjectStatus.Online; service.Update(); } // with the service added to the farm, see if there is a installed instance on the server... // if not, create it SuperCoolServiceInstance serverSvcInstance = new SuperCoolServiceInstance(server, service); serverSvcInstance.Update(true); // install the service proxy into the farm if isn't already installed var serviceProxy = farm.ServiceProxies.GetValue<SuperCoolServiceProxy>(); if (serviceProxy == null) { serviceProxy = new SuperCoolServiceProxy(farm); serviceProxy.Update(true); } } public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { SPFarm farm = SPFarm.Local; SPServer server = SPServer.Local; //Remove all instances var instance = server.ServiceInstances.GetValue<SuperCoolServiceInstance>(); while (instance != null) { server.ServiceInstances.Remove(instance.Id); instance = server.ServiceInstances.GetValue<SuperCoolServiceInstance>(); }
//Uninstall the service proxy var serviceProxy = farm.ServiceProxies.GetValue<SuperCoolServiceProxy>(); if (serviceProxy != null) { farm.ServiceProxies.Remove(serviceProxy.Id); } //Remove service and jobs var service = farm.Services.GetValue<SuperCoolService>(); if (service != null) farm.Services.Remove(service.Id); }
In the Admin folder, you’ll need a default.aspx page which will be the UI to CREATE an instance of your service application. You can also include an admin page here as well.
The code behind from the default page in Admin contains the following code, which is used to create your service application:
var service = SPFarm.Local.Services.GetValue<SuperCoolService>(); if (service == null) throw new InvalidOperationException("The service is not installed."); //// Get the service proxy object SuperCoolServiceProxy serviceProxy = SPFarm.Local.ServiceProxies.GetValue<SuperCoolServiceProxy>(); if (null == serviceProxy) throw new InvalidOperationException("The service proxy is not installed."); var appPoolInput = this.applicationPoolSection as IisWebServiceApplicationPoolSection; using (SPLongOperation operation = new SPLongOperation(this)) { operation.Begin(); SPIisWebServiceApplicationPool pool = null; pool = appPoolInput.GetOrCreateApplicationPool(); if (pool == null) throw new ConfigurationErrorsException("Could not find an application pool to use!!!"); var app = new SuperCool.ServiceLibrary.SuperCoolServiceApplication( this.serviceNameInput.Text, service, pool); app.Update(true); app.Provision(); var serviceAppProxy = new SuperCoolServiceApplicationProxy("Super Cool Service Proxy Thingamajig", serviceProxy, app.Uri); serviceAppProxy.Provision(); SPServiceApplicationProxyGroup.Default.Add(serviceAppProxy); SPServiceApplicationProxyGroup.Default.Update(); //Start the service instance var server = SPServer.Local; var instance = server.ServiceInstances.GetValue<SuperCoolServiceInstance>(); if (instance == null) { //It should be created during feature activation, but if we can't find it - create it here. instance = new SuperCoolServiceInstance(server, service); instance.Update(true); } if (instance != null && instance.Status != SPObjectStatus.Online) instance.Provision(); } this.SendResponseForPopUI();
In case you missed the link, DOWNLOAD THE SERVICE APPLICATION SOURCE HERE. Then you can play along!!! I’ll post more notes on this in the coming weeks after the Thanksgiving celebrations die down.
To all of you, Happy Thanksgiving, and may you have a great season of the holy days.
Daniel Larson