A few weeks ago from our customers we received the task of creating a room reservation service. The customer company is satisfied with the large and very advanced in terms of IT. The customer has many branches throughout Russia and 5-6 meeting rooms in each, employees often fly to hold meetings from one branch to another, and finding a free audience “on the spot” is a real problem. Therefore, it would be nice for an employee to “stake out” a negotiation right from his workplace in Moscow, for example, in Tula and fly with a clear conscience on a business trip. We want to share the experience of creating such a service with the habrosobject.
Analysis
We knew that the customer’s company has an internal portal made on Microsoft SharePoint 2010, which is used daily by about 1,500 employees. Plus, the company is configured Exchange.
As it is known in Exchange, there is already a feature of resource reservation in the company. The whole thing is done with the help of room mailboxes. In fact, each meeting room has its own postal address, and the employee must schedule a meeting with this room. Other users using the mail client can connect to the calendars and look at the date and time the appointment is made. In addition, Outlook 2010 has Room Finder functionality.
')
Read more about mailbox in Exchange
http://technet.microsoft.com/en-us/library/bb124952(v=exchg.141).aspxAnd here - about Room Finder'e
http://support.microsoft.com/kb/2673231It seems everything looks cool and comfortable. However, there are several drawbacks: first, an employee needs Outlook. Secondly, the description of the room is very poor, you can not add a description of resources (board, conference system, etc.) in a visual form.
Accordingly, a thought arose: how would we bring all the visual presentation in SharePoint and at the same time not lose the functionality of Exchange? At the same time I wanted to write less code. But as practice has shown, it could not have done without it :)
In general, let's go!
SharePoint
To create a service, we made three lists: Divisions, Meeting Rooms, Booking of meeting rooms.
Subdivisions are branches in cities.
Meeting rooms are a list for storing rooms and their characteristics, such as:
- title;
- subdivision;
- capacity;
- the presence of a projector in the room, a conference board marker, etc.
- Email address used for integration with MS Exchange.
And finally, the list of armor:
- room;
- meeting date;
- start time;
- end time;
- the author of the reservation.
So, we have lists, but someone has to fill these lists, so we divided users into roles:
- Users can schedule their meetings and conventions, book rooms, or do specialized searches on parameters.
- The administrator of the division rooms can transfer / cancel existing reservations within his unit.
- The administrator creates and edits meeting rooms, as well as a guide with their characteristics - number of seats, projector, board, etc. It has the ability to switch between departments and play the role of the Administrator of the meeting rooms.
Ui
Since at the customer's design, the portal was already stretched, our designers needed to work quite a bit. What they did very well with:
1. User homepage:

2. For a separate link, you can go to the list of rooms. This list displays basic information. Detailed information about the room is displayed by clicking on the name of the room.

3. The “Find Audiences” link displays a two-week calendar. Each cell shows the time, by whom the room is booked and for how long.

4. A separate click on the "plus sign" will be possible to book a meeting room.

Implementation
To make such beauty we needed to write a WCF service that returns json and at the same time works in the context of SharePoint. This problem is solved by correct web.config and the presence of SVC in the ISAPI folder. Much has been written about how to properly configure web.config to send json'a. For example, here:
http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-GuideNext, we made several ASPX pages, added them to the module and implemented all the logic of working with the WCF service via javascript using the knockout framework.
The main problems we have with Exchange. Almost all the necessary functionality is implemented through calls to the
EWS Managed API methods. However, we needed to automatically create mailboxes when creating an item in the list of rooms.
On the Internet, it was found that mailbox can only be created through powershell, and to cause a command from the C # code is not a problem in principle.
We wrote an event receiver on the list of rooms and tried to call the powershell command on the remote server using Runspace and WSManConnectionInfo. However, firstly, it is not safe, and secondly, we did not manage to do this because of the problems of access denial during connection.
As a result, we decided to write another WCF service and deploy it on the server with Exchange. In fact, this service has only one method:
public void CreateRoom(ExchangeRoom Room) { RunspaceConfiguration runspaceConfig = RunspaceConfiguration.Create(); PSSnapInException snapEx = null; PSSnapInInfo psinfo = runspaceConfig.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out snapEx); using (Runspace runSpace = RunspaceFactory.CreateRunspace(runspaceConfig)) { runSpace.Open(); if (!(MailBoxAlreadyExist(Room.Email, runSpace))) { Command createMailbox = new Command("New-Mailbox"); createMailbox.Parameters.Add("UserPrincipalName", Room.Email); createMailbox.Parameters.Add("Name", Room.Name); createMailbox.Parameters.Add("Room"); using (Pipeline pipeLine = runSpace.CreatePipeline()) { pipeLine.Commands.Add(createMailbox); pipeLine.Invoke(); } } else { throw new Exception(" "); } } }
As we wrote above, all the logic of work with us is implemented through a WCF-service, so it was logical to supplement our service with methods for booking a room in Exchange. To do this, we called the service method to create our reservation in Exchange. All the necessary information was placed in Microsoft.Exchange.Data.Appointment, and then with the help of the API a meeting (meeting) was created in the Exchange calendar.
public static void CreateReservation(Reservation reservation) { InitService(); var appointment = new Appointment(service); appointment.Subject = "Meeting"; appointment.Start = new DateTime(reservation.Date.Year, reservation.Date.Month, reservation.Date.Day, reservation.FromTime, 0, 0); appointment.End = new DateTime(reservation.Date.Year, reservation.Date.Month, reservation.Date.Day, reservation.ToTime, 0, 0); string roomMailboxAddress = string.Format("room_{0}@{1}",reservation.RoomId, SharePointConstantString.MailDomain); appointment.Location = reservation.RoomName; appointment.Resources.Add(roomMailboxAddress); appointment.RequiredAttendees.Add(reservation.User.Email); appointment.Save(SendInvitationsMode.SendToAllAndSaveCopy); }
The problem of “backward” synchronization (i.e., when an employee in his calendar via Outlook booked a room) was decided to be solved through a task (timer job). This job collected all the information from Exchange and created the missing armor, and canceled canceled ones.
Total
We managed to create an architecture that allows us to obtain a scalable and flexible solution built on the Microsoft stack of technologies and taking full advantage of the integrated solution. The system is configured and accompanied by standard platform tools.
So today
- the company's management receives unified collaboration tools that increase the efficiency of a large number of employees;
- employees of the company easier, faster and without nerves plan their work and key meetings and meetings;
- IT has got a flexible, scalable solution that comes with standard tools and makes the most out of the box functionality. So, in the transition to the new versions of SharePoint and Exchange special problems will not arise.