Слайдове и код от SharePoint Dev семинара в New Horizons

by Ради Атанасов 6. December 2010 04:21

Благодаря на всички, които успяха да дойдат на семинара на 30ти. Залата беше пълна, но не успях да видя колко хора има онлайн.

Бях обещал да кача материалите от семинара, ето линкове към слайдовете и кода.

Обратната връзка е с висок резултат (мерси!) и получих интересни съвети и прелдложения, който ви обещавам, че ще взема в предвид за следващия семинар, както и в бъдеще.

Tags: , ,

Uploading WSP files programmatically to remote SharePoint farms

by Ради Атанасов 1. December 2010 02: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
  1. string connString = txtConnectionString.Text;
  2.  
  3. SPFarm remoteFarm = SPFarm.Open(connString);
  4.  
  5. remoteFarm.Solutions.Add(txtWSPPath.Text);

Hope this helps!

Tags: ,

Developing custom Health Rules for SharePoint 2010

by Ради Атанасов 20. November 2010 05: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]

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:

  1. Create a class that inherits from Microsoft.SharePoint.Administration.Health.SPHealthAnalysisRule
  2. Override the required methods in SPHealthAnalysisRule. Check() is where the action happens, but also pay attention to SPHealthAnalysisRuleAutomaticExecutionParameters
  3. Create a feature to register the rule definition with SharePoint
  4. (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):

  1. public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
  2. {
  3.     get
  4.     {
  5.         SPHealthAnalysisRuleAutomaticExecutionParameters execParams =
  6.             new SPHealthAnalysisRuleAutomaticExecutionParameters();
  7.  
  8.         execParams.Schedule = SPHealthCheckSchedule.Hourly;
  9.         execParams.RepairAutomatically = false;
  10.         execParams.Scope = SPHealthCheckScope.All;
  11.         execParams.ServiceType = typeof(SPWebService);
  12.  
  13.         return execParams;
  14.     }
  15. }

I use the following code to get all Database servers:

  1. //Get the Database Service
  2. SPDatabaseService spdbservice =
  3.     SPFarm.Local.Services.GetValue<SPDatabaseService>();
  4.                 
  5. //Get all instances of the Database Service
  6. SPServiceInstanceDependencyCollection dbServices = spdbservice.Instances;
  7.                 
  8. //fail the test if no DB servers are found (network is dead)
  9. if (dbServices.Count == 0) return SPHealthCheckStatus.Failed;
  10.  
  11. //The following will enumerate all instances so we can get the servers hostname
  12. foreach (SPDatabaseServiceInstance instance in dbServices)
  13. {
  14.     SPServer dbServer = instance.Server; //each of these is a DB server
  15.  
  16.     if (!PingServer(dbServer.Name)) //ping it
  17.     {
  18.         failedPings++;
  19.     }
  20. }

And here is my ping method:

  1. private static bool PingServer(string serverHostName)
  2. {
  3.     bool returnValue = false;
  4.  
  5.     Ping dbPing = new Ping();
  6.     PingReply reply = dbPing.Send(serverHostName);
  7.  
  8.     if (reply.Status == IPStatus.Success)
  9.     {
  10.         long latency = reply.RoundtripTime;
  11.  
  12.         if (latency <= 1) { returnValue = true; }
  13.     }
  14.  
  15.     return returnValue;
  16. }

Here is the Feature Receiver code to register the rule:

  1. public override void FeatureActivated(SPFeatureReceiverProperties properties)
  2. {
  3.     Assembly currectAssembly = Assembly.GetExecutingAssembly();
  4.  
  5.     try
  6.     {
  7.         SPHealthAnalyzer.RegisterRules(currectAssembly);
  8.         //SPHealthAnalyzer.UnregisterRules(currectAssembly);
  9.     }
  10.     catch (Exception ex)
  11.     {
  12.         throw new Exception("Registering Health Rules from "
  13.             + currectAssembly.FullName + " failed. " + ex.Message);
  14.     }
  15. }

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]

  • The implementation of this can be seen in the AddItem method with Reflector”

clip_image001

Further links:

Download source code: Community.SharePoint.zip (you must click the download button on the Live page...)

Hope this helps !

Tags: , , ,

Microsoft Days 2010 – код и PowerPoint Slides

by Ради Атанасов 17. April 2010 07:58

За мен това беше първият MS Days на който съм присъствал - бях супер доволен. Добра атмосфера, много партньори, добри лекции… дори имаше и бира ?!?!?

Лекцията, която изнесох беше най-техническата на тема SharePoint – искаше ми се да има повече SharePoint (:

Ето и кода, който обещах: PerformanceManagement.zip

Това, за което може да ви е полезен е:

  1. Добавяне на бутон в Ribbon на SharePoint 2010
  2. Link към custom javascript file за този бутон
  3. отваряне на диалогов прозорец с т.н. Dialog Framework
  4. SP2010 webpart, който генерира Office документи с Open XML и Word Automation Services – супер интересно (:
  5. Има и един 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

Поздрави!

Tags: , , , , ,

Използване на LINQ to XML върху резултатите от SharePoint Web Services

by Ради Атанасов 18. March 2010 03: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()” от отговора.

Очаквайте още!

Tags: , , , ,

Using LINQ to XML to process SharePoint web service responses in Silverlight

by Ради Атанасов 18. March 2010 02: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!

Tags: , , , ,

SharePoint meets LINQ to XML: CAML заявки за работа с Lists.asmx

by Ради Атанасов 18. March 2010 01: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.

Успех!

Tags: , , , ,

SharePoint meets LINQ to XML: Building a CAML Query and calling Lists.asmx

by Ради Атанасов 18. March 2010 01: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!

Tags: , , , ,

Forcing the DIP to load when a Word Document loads from SharePoint

by Ради Атанасов 20. February 2010 22: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.

Tags: , , ,

Автоматично показване на DIP когато се отваря Word документ

by Ради Атанасов 20. February 2010 22: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

Дано това помогне на някой.

Tags: , , ,

Microsoft Certified Master

SharePoint Server MVP

Radi Atanassov SharePoint MVP

About Me

SharePoint architect, consultant and solution developer. Owner and Chief SharePoint Architect of OneBit Software.

Аз съм консултант, архитект и разработчик на SharePoint решения. Собственик и Главен Архитект на OneBit Software.

Feeds

Get RSS Feed (Bulgarian)
Get RSS Feed (English)    
Get RSS Feed  (Both)        

I blog about technical concepts in English, as they benefit the whole community, but sometimes I blog about stuff specific to Bulgaria, and those I post in Bulgarian. The above feed URL's let you choose what to subscribe to.

My SharePoint Forum Activity

SharePoint User Group Bulgaria

login