by Ради Атанасов
6. December 2010 13:21
Благодаря на всички, които успяха да дойдат на семинара на 30ти. Залата беше пълна, но не успях да видя колко хора има онлайн.
Бях обещал да кача материалите от семинара, ето линкове към слайдовете и кода.
Обратната връзка е с висок резултат (мерси!) и получих интересни съвети и прелдложения, който ви обещавам, че ще взема в предвид за следващия семинар, както и в бъдеще.
by Ради Атанасов
1. December 2010 11:19
I was researching the possibility to upload a WSP file remotely, without logon access to any SP servers on a farm.
This is possible with the SPFarm.Open method, as long as you have access to the database. Firewalls should also allow access.
I have created a simple solution to demonstrate this: go to this page and click Download
The code to achieve this is fairly simple:
SPFarm.Open
- string connString = txtConnectionString.Text;
-
- SPFarm remoteFarm = SPFarm.Open(connString);
-
- remoteFarm.Solutions.Add(txtWSPPath.Text);
Hope this helps!
by Ради Атанасов
20. November 2010 14:34
What are health rules?
SharePoint 2010 has a new feature called the Health Analyzer and it has Health Rules. Each rule checks a particular metric within the SharePoint farm, and Central Administration provides an interface to see problems, warnings, and rule definitions. Administrators can subscribe to rules so they get alerts when the rule fails. Administrators cannot create custom rules, but developers can.
This is what the interface looks like:
![clip_image001[8] clip_image001[8]](http://www.sharepoint.bg/radi/image.axd?picture=clip_image001%5B8%5D_thumb.png)
Why should architects and developers consider them?
Administrators might ask you to create rules to monitor specific things on a server.
Further to that, developers can create rules to monitor their own solutions. Certain aspects of a solution might be problematic and require attention after time - for example a growing list. A custom rule can monitor this list, and notify certain people if a threshold is being passed.
High-Level steps to create a custom Health Rule:
- Create a class that inherits from Microsoft.SharePoint.Administration.Health.SPHealthAnalysisRule
- Override the required methods in SPHealthAnalysisRule. Check() is where the action happens, but also pay attention to SPHealthAnalysisRuleAutomaticExecutionParameters
- Create a feature to register the rule definition with SharePoint
- (Optional) use a Console Application to test your rule code while developing it. This is much more convenient when you need to debug with Visual Studio 2010.
Example Solution:
I have put together a template you could reuse to build custom health rules. My example pings each database server from each WFE and fails if the ping is greater than 1ms. Download the code from the bottom of the post.
Here is my schedule and scope configuration (see notes below for more details):
- public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
- {
- get
- {
- SPHealthAnalysisRuleAutomaticExecutionParameters execParams =
- new SPHealthAnalysisRuleAutomaticExecutionParameters();
-
- execParams.Schedule = SPHealthCheckSchedule.Hourly;
- execParams.RepairAutomatically = false;
- execParams.Scope = SPHealthCheckScope.All;
- execParams.ServiceType = typeof(SPWebService);
-
- return execParams;
- }
- }
I use the following code to get all Database servers:
- //Get the Database Service
- SPDatabaseService spdbservice =
- SPFarm.Local.Services.GetValue<SPDatabaseService>();
-
- //Get all instances of the Database Service
- SPServiceInstanceDependencyCollection dbServices = spdbservice.Instances;
-
- //fail the test if no DB servers are found (network is dead)
- if (dbServices.Count == 0) return SPHealthCheckStatus.Failed;
-
- //The following will enumerate all instances so we can get the servers hostname
- foreach (SPDatabaseServiceInstance instance in dbServices)
- {
- SPServer dbServer = instance.Server; //each of these is a DB server
-
- if (!PingServer(dbServer.Name)) //ping it
- {
- failedPings++;
- }
- }
And here is my ping method:
- private static bool PingServer(string serverHostName)
- {
- bool returnValue = false;
-
- Ping dbPing = new Ping();
- PingReply reply = dbPing.Send(serverHostName);
-
- if (reply.Status == IPStatus.Success)
- {
- long latency = reply.RoundtripTime;
-
- if (latency <= 1) { returnValue = true; }
- }
-
- return returnValue;
- }
Here is the Feature Receiver code to register the rule:
- public override void FeatureActivated(SPFeatureReceiverProperties properties)
- {
- Assembly currectAssembly = Assembly.GetExecutingAssembly();
-
- try
- {
- SPHealthAnalyzer.RegisterRules(currectAssembly);
- //SPHealthAnalyzer.UnregisterRules(currectAssembly);
- }
- catch (Exception ex)
- {
- throw new Exception("Registering Health Rules from "
- + currectAssembly.FullName + " failed. " + ex.Message);
- }
- }
The commented out line lets you unregister the rule. You should do this in the Deactivating method.
Important Points in configuring the scope and schedule of you rule:
- The ServiceType property - this lets you specify a particular SharePoint service that is required on servers that are to run this rule. For example, you can use this property to specify that your rule should only run on machines running Excel Services.
- The Scope property - this defines whether the rule will run on ALL servers, or ANY servers. If set to ANY, it will run on the first server that is running the SharePoint Service specified in the ServiceType property. If set to ALL, it will run on all servers running that service.
- In my example I am pinging the DB servers from ALL servers running the SharePoint Web Service (web front ends). Any application server not running this service will not fire this rule. You might want to change this to SPTimerService or whatever suits your needs.
Other things of interest:
- Central Administration has a “HealthRules” list, which has it’s own List Template type (SPHealthRulesList).
- The SPHealthAnalyzer object maintains this feature.
- The AddItem method of the SPHealthRulesList does two things: Creates an Item in the List, then registers an SPHealthAnalyzerJobDefinition Timer Job. There is one of these for each schedule, service and scope. This can be seen in the Timer Job definitions page:
![clip_image001[5] clip_image001[5]](http://www.sharepoint.bg/radi/image.axd?picture=clip_image001%5B5%5D_thumb_1.png)
- The implementation of this can be seen in the AddItem method with Reflector”

Further links:
Download source code: Community.SharePoint.zip (you must click the download button on the Live page...)
Hope this helps !
by Ради Атанасов
17. April 2010 16:58
За мен това беше първият MS Days на който съм присъствал - бях супер доволен. Добра атмосфера, много партньори, добри лекции… дори имаше и бира ?!?!?
Лекцията, която изнесох беше най-техническата на тема SharePoint – искаше ми се да има повече SharePoint (:
Ето и кода, който обещах: PerformanceManagement.zip
Това, за което може да ви е полезен е:
- Добавяне на бутон в Ribbon на SharePoint 2010
- Link към custom javascript file за този бутон
- отваряне на диалогов прозорец с т.н. Dialog Framework
- SP2010 webpart, който генерира Office документи с Open XML и Word Automation Services – супер интересно (:
- Има и един web service в SP 2010
Ето и презентацията: MS Days Radi Atanassov
Аз лично бях доволен от лекцията, въпреки че забравих да покажа генерираните PDF и XPS files…
Ето го и рейтинга ми:
|
Ради Атанасов
|
Архитектура и изграждане на бизнес приложения с SharePoint 2010, Silverlight и Open XML SDK (Ниво: 300)
|
79
|
Oбща оценка на презентацията
|
7.85 / 9
|
|
Ради Атанасов
|
Архитектура и изграждане на бизнес приложения с SharePoint 2010, Silverlight и Open XML SDK (Ниво: 300)
|
79
|
Компетентност на лектора
|
8.08 / 9
|
|
Ради Атанасов
|
Архитектура и изграждане на бизнес приложения с SharePoint 2010, Silverlight и Open XML SDK (Ниво: 300)
|
79
|
Предоставената информация е полезна за моята работа
|
7.46 / 9
|
|
Ради Атанасов
|
Архитектура и изграждане на бизнес приложения с SharePoint 2010, Silverlight и Open XML SDK (Ниво: 300)
|
79
|
Презентационни умения на лектора
|
7.54 / 9
|
Поздрави!
by Ради Атанасов
18. March 2010 12:02
Когато работиме със Silverlight имаме възможност да използваме LINQ to XML за извличане на данни от резултатите от SharePoint Web Services. Тези дни разгледах LINQ to XML и никога повече не бих работил с XmlDocument обектите (:
Ето няколко примера:
GetListItems() – това е метод от Lists.asmx, и ето му отговора:
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="13">
<z:row ... ows_ContentType="Task" ows_Title="New Task 1" ... />
... more rows here
</rs:data>
</listitems>
За да извлечем заглавията на list items и да ги подредим в List<string> обект:
private List<string> ProcessListResults(SPListsWS.GetListItemsCompletedEventArgs e)
{
string result = e.Result.ToString();
XNamespace ns = "#RowsetSchema";
XElement results = new XElement(e.Result);
var listItems = from x in results.Descendants(ns + "row")
where x.Attribute("ows_Title") != null
select x;
List<string> itemsList = new List<string>();
foreach (var item in listItems)
{
string title = item.Attribute("ows_Title").Value;
itemsList.Add(title);
}
return itemsList;
}
GetUserInfo() – Този метод е от usergroup.asmx и ни дава информация за user в текущия SPSite обект (взима го от скрития user list). Ето отговора:
<GetUserInfo xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
<User ID="7" Sid="S-1-5-21-347908140-582334945-263120918-1111" Name="Radi"
LoginName="DEV\radi" Email="" Notes="" IsSiteAdmin="False"
IsDomainGroup="False" />
</GetUserInfo>
И как извлиам LoginName:
public static string GetLoginFromServiceResponse(XElement result)
{
XNamespace ns = "http://schemas.microsoft.com/sharepoint/soap/directory/";
XName xUser = XName.Get("User", ns.NamespaceName);
XName xUserInfo = XName.Get("GetUserInfo", ns.NamespaceName);
XElement user = result.Element(xUser);
if (user != null) { return user.Attribute("LoginName").Value; }
return null;
}
Това което подавам на метода е “e.Result.ToString()” от отговора.
Очаквайте още!
by Ради Атанасов
18. March 2010 11:53
Since working with LINQ to XML, I’ve totally fallen in love with it and could never go back to working with the XmlDocument objects.
Here are a few code snippets that can help you out. It is so simple once you get a hang of it.
GetListItems() – this Lists.asmx method returns the following response:
<listitems xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"
xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<rs:data ItemCount="13">
<z:row ... ows_ContentType="Task" ows_Title="New Task 1" ... />
... more rows here
</rs:data>
</listitems>
To get the value of the title into a List<string> object:
private List<string> ProcessListResults(SPListsWS.GetListItemsCompletedEventArgs e)
{
string result = e.Result.ToString();
XNamespace ns = "#RowsetSchema";
XElement results = new XElement(e.Result);
var listItems = from x in results.Descendants(ns + "row")
where x.Attribute("ows_Title") != null
select x;
List<string> itemsList = new List<string>();
foreach (var item in listItems)
{
string title = item.Attribute("ows_Title").Value;
itemsList.Add(title);
}
return itemsList;
}
GetUserInfo() – this method is inside usergroup.asmx and gives us information regarding a user in an SPSite object. The response:
<GetUserInfo xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
<User ID="7" Sid="S-1-5-21-347908140-582334945-263120918-1111" Name="Radi"
LoginName="DEV\radi" Email="" Notes="" IsSiteAdmin="False"
IsDomainGroup="False" />
</GetUserInfo>
To get the LoginName:
public static string GetLoginFromServiceResponse(XElement result)
{
XNamespace ns = "http://schemas.microsoft.com/sharepoint/soap/directory/";
XName xUser = XName.Get("User", ns.NamespaceName);
XName xUserInfo = XName.Get("GetUserInfo", ns.NamespaceName);
XElement user = result.Element(xUser);
if (user != null) { return user.Attribute("LoginName").Value; }
return null;
}
The passed in “result” is derived from e.Result.ToString().
Hope this helps!
by Ради Атанасов
18. March 2010 10:28
Напоследък ми се налага да работя с LINQ to XML за интеграционни сценарии включващи Silverlight и SharePoint. LINQ to XML е страхотно – сравнително по-добре от създаване на XML чрез обекти като XmlDocument.
Ето пример – повиквам GetListItems() метода на Lists.asmx. Със следният код извличам list items от Task списъка създадени от специфичен user. Този пример би трябвало да работи както за WSS v3, така и за MSF v4.
XElement query = new XElement("Query",
new XElement("Where",
new XElement("Eq",
new XElement("FieldRef", new XAttribute("Name", "Author"), new XAttribute("LookupId", "True")),
new XElement("Value", new XAttribute("Type", "User"), userID)
)));
XElement queryOptions = new XElement("QueryOptions");
XElement viewFields = new XElement("ViewFields");
_listService.GetListItemsAsync("Tasks", null,
query, viewFields, "100", queryOptions, null, null);
userID e SharePoint ID-то на потребителя, за който искам да видя резултатите. Можете да получите тази информация от usergroup.asmx.
Успех!
by Ради Атанасов
18. March 2010 10:20
I’ve been playing around with LINQ to XML and Silverlight recently, and it is absolutely awesome! The amount of code you have to write compared to working with XML DOM objects like XmlDocument is extremely minimised.
Here is an example on calling the GetListItems() method of Lists.asmx. I am returning the top 100 items in a Task list that are created by a particular user. This code example should be compatible for both WSS v3 and MSF v4.
XElement query = new XElement("Query",
new XElement("Where",
new XElement("Eq",
new XElement("FieldRef", new XAttribute("Name", "Author"), new XAttribute("LookupId", "True")),
new XElement("Value", new XAttribute("Type", "User"), userID)
)));
XElement queryOptions = new XElement("QueryOptions");
XElement viewFields = new XElement("ViewFields");
_listService.GetListItemsAsync("Tasks", null,
query, viewFields, "100", queryOptions, null, null);
userID is the SharePoint user value within the current SPSite. You can get this with the usergroup.asmx service.
Hope this helps!
by Ради Атанасов
21. February 2010 07:47
I was working on a project and I had custom content types defined in a feature. These content types had document templates, and I wanted to control the Document Information Panel (DIP) when a document is opened in Word.
The following code snippet takes an SPContentType object and adds a custom XSN element to the content types XmlDocuments collection. Setting the openByDefault value to “True” will force the DIP to open when the document loads. I use a FeatureReceiver to run this code against a newly provisioned Content Type.
public static void ConfigureContentTypes(SPContentType ct)
{
XmlDocument doc = GetCustomXsnDocument();
ct.XmlDocuments.Add(doc);
ct.Update(true);
}
private static XmlDocument GetCustomXsnDocument()
{
XmlDocument doc = new XmlDocument();
string xml = "<customXsn xmlns=\"http://schemas.microsoft.com/office/2006/metadata/customXsn\"><xsnLocation></xsnLocation><cached>True</cached><openByDefault>True</openByDefault><xsnScope></xsnScope></customXsn>";
doc.LoadXml(xml);
return doc;
}
You can find information about the child CustomXsn elements on this MSDN link: Content Type Document Information Panel Schema
Hope this helps.
by Ради Атанасов
21. February 2010 07:45
Работя по един проект, в който имам дефинирани Content Types в Feature. Тези Content Types имат различни document templates, и ми се наложи да конфигурирам Document Information Panel (DIP) да се отваря автоматично. Това става лесно чрез интерфейса, но трябваше да е част от автоматизиран деплоймент.
В следващия код показвам как става това. Подаваме SPContentType обект, на който му се дефинира нов CustomXsn елемент в своята XmlDocuments колекция. Ако под-елемента openByDefault е “True”, DIP ще се покаже при отварянето на документа. Използвам FeatureReceiver за прекарам мойте Content Types през този статичен метод:
public static void ConfigureContentTypes(SPContentType ct)
{
XmlDocument doc = GetCustomXsnDocument();
ct.XmlDocuments.Add(doc);
ct.Update(true);
}
private static XmlDocument GetCustomXsnDocument()
{
XmlDocument doc = new XmlDocument();
string xml = "<customXsn xmlns=\"http://schemas.microsoft.com/office/2006/metadata/customXsn\"><xsnLocation></xsnLocation><cached>True</cached><openByDefault>True</openByDefault><xsnScope></xsnScope></customXsn>";
doc.LoadXml(xml);
return doc;
}
Можете да намерите повече информация за CustomXsn елемента на този MSDN линк: Content Type Document Information Panel Schema
Дано това помогне на някой.