Menu SharePoint
Architecture
WEB APPLICATION http://hostname:port
- Site Collection Default http://hostname:port
- Web Default (SubSite) http://hostname:port/Pages/default.aspx
- Web 1 (SubSite) http://hostname:port/SubSite/subsite1/Pages/default.aspx
- Web 2 (SubSite) http://hostname:port/SubSite/subsite2/Pages/default.aspx
- Web x (SubSite)
- Site Collection 1 http://hostname:port/sites/site1
- Web Default http://hostname:port/sites/site1/Pages/default.aspx
- Web 1 http://hostname:port/sites/site1/SubSite/subsite1/Pages/default.aspx
- Web 2
- Web x
- Site Collection 2 http://hostname:port/sites/site2
- Web Default
- Web 1
- Web 2
- Web x
All the physical files asp for sharepoint are in the repertory :
F:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE \Feature,layout ....
Global assembly cache
When we use an Assembly, the assembly is loaded in the GAC and when we don't use it
the garbage collector detroy the new instance of the assembly.
A DLL is a dynamic librairy that contain managed code.
When we compile a project that create a Dll that contains everything except the file XML ...
Assembly = namespace.
public token = 12345..99 = number of the assembly
version = 1.0.0.0
If we want a new version we compile in VStudio with a new version number.
To enter the dll ImportFiles into the GAC we type :
F:\Program Files (x86)\Microsoft Visual Studio 11.0>gacutil /i F:\ImportFiles.dll
To do it we need a strong signature = unique name
Strong name
The dll will be in the directory, if is is a dll that we have developped :
F:\Windows\Microsoft.NET\assembly\GAC_MSIL
Dll in GAC 2
If it is a Microsoft assembly it is in :
F:\Windows\assembly
Dll of the GAC
Deploy
The Deploy install the programs in Sharepoint, install here the job timer(feature).
Deploy install in gac, or the build do it ?
Deploy
For a job timer, after each deploy do a reset of the "service job timer".
PowerShell services.msc
Debug
To debug a program in sharepoint we need to attach the program to IIS (w3wp.exe)
Attach
Step of loading a page
URL -> IIS -> Application pool
- Creation d'un pipeline
- The pipeline want to load for example the page default.aspx.
1) loading of the modules (the module is in webconfig)
(the module is done for deal with the page)
2) load the httpHandler (The httpHandler is in webConfig)
httphandler is for a specific URL // ? check it.
3) In the page Client, server, client
4) page html
When we create a new item in the list, the new item has an URL : :ShareDocument.../document.txt.
When loading this URL, we load before the event receiver (event handler) before that the page is shown.
List : Display column in a list
List of column visible
Using (to detroy the object after use)
using(SPSite spSite = new SPSite(url))
{
using(SPWeb spWeb = spSite.OpenWeb())
{
}
}
using at the end of {}, do a Dispose of the ressources (here spSite, and spWeb) in the case of the object has
a method Disposable. It is the same thing to write : spSite.Dispose(), spWeb.dispose();
Here in our example we have 2 differents instances, so the need 2 using. Using is for one object.
The reason to use using is that the object spSite is an object sharepoint and this object is
not free by the garbage collector. This is the same for SQL object. At the end we must write :
sqlConnection.close().
In this example we cannot use using, using doesn't work in a foreach loop
foreach (SPSite spSite in webaplication.sites)
{
string titleName = spSite.title ... //the title opens object linked to object spSite.
//that means that if I close spSite, I close also
//the objects linked.
spSite.dispose();
}
Note :
------
If we use :
SPSite spSite = SPcontext.site();
spSite.dispose() kill the current Site for the user, and the program
will not work propely. Because here we don't write = new(), so we didn't create
a new instance, so we do need to do dispose !!!!!
Event Receiver
Event Receive in sharepoint is like event handler in C#.
Event handler is for validate data and test the permissions.
project, add New event receiver
Event receiver can be of type List item event, list event, web.
list event : When we create a new List.
list item event : When we add a new item in a list.
web : When we create a new subsite, we need it because secretaries are creating new subsite.
we choose the type of event we want to have ex : delete, create, update , before and after.
We get : ItemAdding, ItemAdded, ItemUpdateing, ItemUpdated, ItemDeleting, ItemDeleted.
We choose also the scope, site or web.
ex ItemUpdating(....)
{
base......
string beforeValue = properties.BeforeProperties["Title"].toSting(); -> NULL
string afterValue = properties.AfterProperties["Title"].toSting(); -> NULL
SPList spListItem = properties.ListItem; -> ok
spListItem["title"].toString -> old value
//==> //todo
read the new value in the itemUpdating.
//Cancel must be done here and not in the updated.
//updated the modification is already done in the database.
properties.status = SPEventStatus.cancel;
//==> //todo
check the permission : spListItem.doesUserPermission...
}
If we did a insert, the insert do also an update.
Add Event receiver
First do a new Empty sharepoint project.
Event receiver can be for event of type list, list event, web ...
Event Receiver
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
namespace SharePointEventReceiver.EventReceiver1
{
///
/// List Item Events
///
public class EventReceiver1 : SPItemEventReceiver
{
///
/// An item is being added.
///
public override void ItemAdding(SPItemEventProperties properties)
{
base.ItemAdding(properties);
string beforeValue = properties.BeforeProperties["Title"].ToString();
string afterValue = properties.AfterProperties["Title"].ToString();
SPListItem currentItem = properties.ListItem;
}
///
/// An item is being updated.
///
public override void ItemUpdating(SPItemEventProperties properties)
{
base.ItemUpdating(properties);
// string beforeValue = properties.BeforeProperties["Title"].ToString();
// string afterValue = properties.AfterProperties["Title"].ToString();
//properties.Status = SPEventReceiverStatus.CancelNoError; //Code to cancel the update
}
///
/// An item is being deleted.
///
public override void ItemDeleting(SPItemEventProperties properties)
{
base.ItemDeleting(properties);
string beforeValue = properties.BeforeProperties["Title"].ToString();
string afterValue = properties.AfterProperties["Title"].ToString();
SPListItem currentItem = properties.ListItem;
}
///
/// An item was added.
///
public override void ItemAdded(SPItemEventProperties properties)
{
base.ItemAdded(properties);
string beforeValue = properties.BeforeProperties["Title"].ToString();
string afterValue = properties.AfterProperties["Title"].ToString();
SPListItem currentItem = properties.ListItem;
}
///
/// An item was updated.
///
public override void ItemUpdated(SPItemEventProperties properties)
{
base.ItemUpdated(properties);
// string beforeValue = properties.BeforeProperties["Title"].ToString();
// string afterValue = properties.AfterProperties["Title"].ToString();
// SPListItem currentItem = properties.ListItem;
properties.Status = SPEventReceiverStatus.CancelNoError;
}
///
/// An item was deleted.
///
public override void ItemDeleted(SPItemEventProperties properties)
{
base.ItemDeleted(properties);
string beforeValue = properties.BeforeProperties["Title"].ToString();
string afterValue = properties.AfterProperties["Title"].ToString();
SPListItem currentItem = properties.ListItem;
}
}
}
Feature
Feature is for publish the object into the sharepoint. The feature will create a file.wsp.
In all project VS with SharePoint there is feature and the feature must be activated into the central sharepoint
To insert manually a feature into Sharepoint
Install-SPFeature -path "ImportFilesFeatures" -CompatibilityLevel 15 -force
ImportFilesFeatures is the folder that contains the file feature.
F:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\FEATURES\ImportFilesFeatures
Feature.xml :
Job timer
Job timer, we need to do a new feature that will install a job that
will run at a specific time. In the first example we install the job timer manually.
This file is if we install manually.
Identity
In 2013, the deploy install the components in sharepoint. The XML file is different
Feature
class , event activate and desactivate in the feature
-----------------------------------------------------
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace ImportFiles
{
///
/// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
///
///
/// The GUID attached to this class may be used during packaging and should not be modified.
///
[Guid("0e8416d4-9428-47c3-afea-9ca6fe7c92e5")]
public class FeatureEventReceiver : SPFeatureReceiver
{
public string myJobName = "ListenerFiles";
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
try
{
SPWebApplication webApp = (SPWebApplication)properties.Feature.Parent;
//Good Practice to delete the older version of Job if it exists
foreach (SPJobDefinition job in webApp.JobDefinitions)
{
if (job.Name.ToLower() == myJobName.ToLower())
{
job.Delete();
}
}
//Install the job definition
ListenerFiles tempJob = new ListenerFiles(myJobName, webApp);
//If you want to run it every hour, use SPHourlySchedule class to configure.
//This one will run between 0 to 5 mintues of every hour
SPHourlySchedule schedule = new SPHourlySchedule();
schedule.BeginMinute = 0;
schedule.EndMinute = 5;
tempJob.Schedule = schedule;
tempJob.Update();
}
catch (Exception ex)
{
}
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
try
{
SPWebApplication webApp = (SPWebApplication)properties.Feature.Parent;
//delete the job
foreach (SPJobDefinition job in webApp.JobDefinitions)
{
if (job.Name.ToLower() == myJobName.ToLower())
{
job.Delete();
}
}
}
catch (Exception ex)
{
}
}
}
}
//============//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace ImportFiles
{
class ListenerFiles : SPJobDefinition
{
public ListenerFiles()
: base()
{
}
public ListenerFiles(string jobName, SPService service, SPServer server, SPJobLockType targetType)
: base(jobName, service, server, targetType)
{
}
public ListenerFiles(string jobName, SPWebApplication webApplication)
: base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
{
this.Title = "Import Files";
}
public override void Execute(Guid contentDbId)
{
// get a reference to the current site collection's content database
SPWebApplication webApplication = this.Parent as SPWebApplication;
SPContentDatabase contentDb = webApplication.ContentDatabases[contentDbId];
// get a reference to the "Tasks" list in the RootWeb of the first site collection in the content database
SPList taskList = contentDb.Sites[0].RootWeb.Lists["Tasks"];
// create a new task, set the Title to the current day/time, and update the item
SPListItem newTask = taskList.Items.Add();
newTask["Title"] = DateTime.Now.ToString();
newTask.Update();
}
}
}
SharePoint WCF
When we do a WCF for sharepoint there is less problem of authorisation to access site, web, list...
There is a good link :
http://www.robertseso.com/2013/05/adding-custom-wcf-services-to.html
1) add a Mapped folder in the folder ISAPI
WCF
In the directory ISAPI, there is a new folder ImportFileService. the address of the WCF will be
n2mnpb4oi4e:9001/_vti_bin/ImportFilesService/ImportFilesService.svc.
We can open the IIS, site that we want and see the repertory the ISAPI.
WCF
Ex of code to insert a file in a list
//spWeb.AllowUnsafeUpdates is if they are security problems.
//lock is use for a loop to avois to call sereral time the web service
private void btn_FillList_Click(object sender, EventArgs e)
{
url = Txt_SiteUrl.Text;
using (SPSite siteCollection = new SPSite(url))
{
using (SPWeb spWeb = siteCollection.OpenWeb())
{
try
{
spWeb.AllowUnsafeUpdates = true;
SPList spList = spWeb.Lists["List1TestImport"];
string fileName = "toto4.txt";
FileStream fileStream = null;
Byte[] fileContent = null;
try
{
// windows service side
string docPath = "F:\\tmp\\";
fileStream = File.OpenRead(docPath + fileName);
fileContent = new byte[Convert.ToInt32(fileStream.Length)];
fileStream.Read(fileContent, 0, Convert.ToInt32(fileStream.Length));
/* NORMAL CODE
spList.RootFolder.Files.Add(spList.RootFolder.Url + "/" + fileName, fileContent, true);
spList.Update();
*/
//CODE USED IF WE WANT TO USE BASE64 (Can be used to call a web service)
//This part of code must be in the WebService
string steamBase64 = Convert.ToBase64String(fileContent);
Byte[] byteFromStringStream = Convert.FromBase64String(steamBase64);
// web service side
objLock = 1;
lock (objLock)
{
using (MemoryStream ms = new MemoryStream(byteFromStringStream))
{
SPFile spFile = spList.RootFolder.Files.Add(spList.RootFolder.Url + "/" + fileName, ms.ToArray(), true);
SPListItem spListItem = spFile.Item;
spListItem["Name"] = fileName + "_New";
spListItem["Title"] = fileName + "_NewTitle";
spListItem.Update();
objLock = null;
}
}
}
catch (Exception ex)
{
}
finally
{
if (fileStream != null)
{
fileStream.Close();
}
}
}
finally
{
spWeb.AllowUnsafeUpdates = false;
}
}
}
}
//=== Other example ===
SPSite site = new Microsoft.SharePoint.SPSite("http://localhost");
SPWeb spWeb = site.RootWeb;
SPList docLib = spWeb.Lists["My Document Library"];
SPListItem folder = docLib.Folders.Add(docLib.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, "My folder");
folder.Update();
t ha
using (FileStream fs = File.OpenRead (@"C:\TestDoc.doc"))
{
SPFile file = folder.Folder.Files.Add("TestDoc.doc", fs);
file.Update();
}
Proxy call WCF in job timer
To create a proxy = (passerelle en francais) go to : Search VS2012 X64 cross tools command
svcutil.exe http://win-n2mnpb4oi4e:9001/_vti_bin/ImportFilesService/ImportFilesService.svc /out:F:\ImportFilesServiceProxy.cs
Proxy
In the job timer we use a proxy because the job timer is in the central application in not in the web application.
So the job timer when we run it doesn't know where to find the WCF.
When the just timer is running the proxy give the address of the WCF.
//The proxy contains the definition of the serializable objects :
namespace ImportFilesService
{
using System.Runtime.Serialization;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="TypeFileAndList", Namespace="http://schemas.datacontract.org/2004/07/ImportFilesService")]
public partial class TypeFileAndList : object, System.Runtime.Serialization.IExtensibleDataObject
{
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private string NameOfFileField;
private string NameOfFolderField;
private string NameOfUserField;
private Microsoft.SharePoint.SPBasePermissions SPBasePermissionCallerField;
private string SteamBase64Field;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData
{
get
{
return this.extensionDataField;
}
set
{
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string NameOfFile
{
get
{
return this.NameOfFileField;
}
set
{
this.NameOfFileField = value;
}
}
...
//To call the proxy in the code :
using (ImportFilesServiceClient refWcf0 = ConfigureProductCatalogProxy())
{
ImportFilesService.TypeFileAndList obj0 = new ImportFilesService.TypeFileAndList();
obj0.SteamBase64 = "";
obj0.NameOfFile = "";
//obj2.NameOfFolder = allFolders[allFolders.Length - 1];
obj0.NameOfFolder = folderNameShort;
obj0.NameOfUser = "Administrateur";
obj0.NameOfList = ListName;
if (obj0.NameOfFolder.Contains("D1"))
{
// obj2.SPBasePermissionCaller = (SPBasePermissions)SPContext.Current.Web.RoleDefinitions.GetByType(SPRoleType.Contributor).BasePermissions;
}
else
{
// obj2.SPBasePermissionCaller = SPContext.Current.Web.RoleDefinitions.GetByType(SPRoleType.Reader).BasePermissions;
}
string result0 = refWcf0.InsertInList(obj0);
}
//In the call we define the binding and the client (same thing that a reference)
private ImportFilesServiceClient ConfigureProductCatalogProxy()
{
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
// Replace with the name of the development server.
EndpointAddress remoteAddress = new EndpointAddress("http://win-n2mnpb4oi4e:9001/_vti_bin/ImportFilesService/ImportFilesService.svc");
ImportFilesServiceClient client = new ImportFilesServiceClient(binding, remoteAddress);
using (HostingEnvironment.Impersonate())
{
client.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
}
return client;
}
Web config
for each site, there is a wb config.
A job timer has also a job config in 15\bin OWSTIMER.EXE.CONFIG
We can add a parameter in the tag
//To call it in the program :
string importFolder = ConfigurationManager.AppSettings["ImportFileDirPath"];
string ListName = ConfigurationManager.AppSettings["ImportListName"];
if (spList.DoesUserHavePermissions(SPBasePermissions.AddListItems))
Permissions
if (spList.DoesUserHavePermissions(SPBasePermissions.AddListItems))
Application pool identity
In order to the web service receive right to read sharepoint database, the web service
must have a account Administrateur. If not site = new Site("url") doesn't work
Or we can do a Web service sharepoint in that have all the permissions.
Identity
Visual Web part
We must write all the code by ourself, onClick ....
Web part
Web part
Application page
project : VisualWebPartProject2, page : ApplicationPage1.aspx
After deploy :
F:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\VisualWebPartProject2
Page
//To do an application page :
- do a new empty sharepoint project
- Give application
It is important to know that the page aspx will be for all sharepoint and not just for this application.
- When we do "Deploy" the page aspx is installed in 15, and will be know by sharepoint,
but it is important to anderstand that the page is not in SQL.
The 15 is just for sharepoint and not for a normal ASP.
If we create a page in Sharepoint, Setting -> Add a page, this page will be only in Sharepoint and not in the 15.
It is the same if we create in sharepoint a page layout by the sharepoint designer. The page layout will be in SQL and not in 15.
Page
The is in all the web application, here in central administration and in webAppljp2
Page
Page layout - SharePoint designer
With the designer we can create a new page layout
Designer
We must do "Check in"
Designer
To use it as a page layout, we must publish a major version
Designer
If we create a new page the new layout appears in the list of the page layout.
Designer
//To add a new site content type of type layout.
//Go to page settings and type create, and create a new content type of type "Page Layout Content Type".
After go to the list of the pages, Librairy settings, and click on "Add from existing site content types"
Designer
Designer
Language notes
//====var====
var = anonyme type if we don't know the type
using (var memoryStream = new MemoryStream())
or write this
using (MemoryStream memoryStream = new MemoryStream())
When the program run the variable of the good type is created.
//====MemoryStream====
MemoryStream is a type for bytes that have a lot of function.
//====Boxing - unBoxing===
int i = 10; // a place is reserved in the memory for the integer.
object obj = i; // obj is a reference (pointeur) that reference the variable i.
j = (int)obj; // the content of the reference of the obj is copied into j.