Showing posts with label SharePoint. Show all posts
Showing posts with label SharePoint. Show all posts

Customize ReportViewerWebPart in C# and render in SharePoint Pages

This is one of the major milestone I have achieved recently to customize the report viewer web part for SharePoint sites. The issue I was facing: the SharePoint site which I have developed was too complex and it exposed via 3 zones. http://intranetsite, http://extranetsite, https://internetsite
  1. http://intranetsite – which is Windows based authentication site and for intranet people.
  2. http://extranetsite – Which is Windows based authentication site and for extranet people
  3. http://internetsite – Which is Forms based authentication site and for internet people.

For each sub site in our implementation it should show the SSRS dashboard report of the site we are in which will contains all information of the site through reports. But, SSRS reporting services and report viewer web part has a limitation in SharePoint integration mode:

System.Web.Services.Protocols.SoapException: The specified path refers to a SharePoint zone that is not supported. The default zone path must be used. ---> Microsoft.ReportingServices.Diagnostics.Utilities.SecurityZoneNotSupportedException: The specified path refers to a SharePoint zone that is not supported. The default zone path must be used.

For example, you have added a report viewer web part to a SharePoint page. And when you opened the site in any other zones other than default zone then you will see above exception. So, how to solve this problem??? No way without customizing the default ReportViewerWebPart. So, I chosen this method and the implementation I have done is working very well.

Implementation:
  1. Create a simple C# Project in Visual Studio to create a web part.
  2. The web part contains logic to render Report Viewer Web Part.
  3. The Report Viewer Web Part will take the default zone web url to render reports.
  4. Supply report parameters to the report viewer.
  5. Add any properties to the report viewer web part like toolbar mode, document map mode etc.
CODE:
public class CustomReportViewerWebPart : System.Web.UI.WebControls.WebParts.WebPart
{
#region Properties

#endregion // Properties

#region Constructors

public CustomReportViewerWebPart()
{
this.ExportMode = WebPartExportMode.All;
}

#endregion // Constructors

#region Privates

//-----------------------------------------------------------------
//Simple error handler for pre-render subs
//-----------------------------------------------------------------
private void HandleErrors(Exception ex)
{
Page.Response.Write(ex.ToString());
}

#endregion // Privates

#region Overrides

//-----------------------------------------------------------------
//Render this Web Part to the output parameter specified.
//-----------------------------------------------------------------

protected override void CreateChildControls()
{
base.CreateChildControls();

try
{
ReportViewerWebPart wp = new ReportViewerWebPart();
this.ChromeType = wp.ChromeType = PartChromeType.None;
wp.PromptAreaMode = CollapsibleDisplayMode.Hidden;
wp.ToolBarMode = ToolBarDisplayMode.None;

string defaultZoneURL = ConfigurationManager.AppSettings["SharePoint_Default_Zone_URL"];
if (string.IsNullOrEmpty(defaultZoneURL))
defaultZoneURL = "http://defaultzoneurl";

string reportPath = ConfigurationManager.AppSettings["SP_Report_Path"];
if (string.IsNullOrEmpty(reportPath))
reportPath = "reportpath"; //If it is the same report everywhere then use it. Otherwise create a web part property. So that user can input report path and use it here.

string parameter1 = "parameter1 value";

if (!string.IsNullOrEmpty(defaultZoneURL))
{
if (defaultZoneURL.EndsWith("/"))
defaultZoneURL = defaultZoneURL.Trim('/');

wp.ReportPath = string.Format("{0}{1}", defaultZoneURL, reportPath);

ReportParameterDefaultCollection parame = wp.OverrideParameters;
parame.Add(new ReportParameter("Parameter1", parameter1)); //Add all report parameters here.
Height = Unit.Pixel(1000);
wp.Height = Height.ToString(); //If you are using single report everywhere then you can hard-coded the height property. Otherwise leave it.

this.Controls.Add(wp);
}
}
catch (Exception ex)
{
Literal litMsg = new Literal();
litMsg.Text = "There is some problem in rendering the dashboard report. Please try again later." + ex.Message;
this.Controls.Add(litMsg);
}
}
#endregion //Overrides
}
I believe the above code is simple to understand and you got it. Please let me know if there are any issues in understanding or run this code. I am always here to help.

Conclusion:
With the above code, you can solve the problem of viewing the report in any zone not only other than "SharePoint default Zone".

Limitation:
As we are customizing the report viewer web part through code, we cannot make the webpart works for all reports. If there are one or two reports in your site and they are in use everywhere then this will be a perfect solution. So, I will work on doing this applying for all reports in couple of days and post in this blog.

Note:
The ReportViewerWebPart class will be reside in the namespace "Microsoft.ReportingServices.SharePoint.UI.WebParts" in the DLL "Microsoft.ReportingServices.SharePoint.UI.WebParts.DLL". The DLL will not be available directly through the file system. You have to get it from GAC. To get it, please follow my another post "How to get the files from GAC in Windows".

This will not be a problem in the new version of Sql Server. Sql Server 2008 R2 AAM has solved this problem. So, this solution will be helpful to the people who are still on earlier versions of 2008 R2. 
Read More...

Set Page Layout programatically for a publishing page

If you like to create pages in site through code then you have to set the page layout for the page. Below is the simple code which does that works well.
private static void SetPageLyoutToPublishibPage()
{
using (SPSite site = new SPSite("http://SP2010Site"))
{
using (SPWeb web = site.OpenWeb())
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
PageLayout pageLayout = null;
foreach (PageLayout p in publishingWeb.GetAvailablePageLayouts())
if (p.Name.Equals("BlankWebPartPage.aspx", StringComparison.InvariantCultureIgnoreCase))
{
pageLayout = p;
break;
}

PublishingPage page = publishingWeb.GetPublishingPage(web.ServerRelativeUrl + "/Pages/Default.aspx");
page.CheckOut();
page.Layout = pageLayout;
page.Update();
page.CheckIn("");
}
}
}
Any issues, please post it here.
Read More...

Set default Page Layout for a SharePoint site

Before reading this post, please take a look at this post: Get default Page Layout for a SharePoint site.
Setting default page layout to a SharePoint site is very important. For example if you are trying to create a new site/web template in SharePoint and from it you like to create sites then do not forget to set default page layout [especially in SharePoint 2010].
private static void SetDefaultPageLayout()
{
using (SPSite site = new SPSite("http://SP2010Site"))
{
using (SPWeb web = site.OpenWeb())
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
PageLayout pageLayout = null;
foreach (PageLayout p in publishingWeb.GetAvailablePageLayouts())
if (p.Name.Equals("BlankWebPartPage.aspx", StringComparison.InvariantCultureIgnoreCase))
{
pageLayout = p;
break;
}
publishingWeb.SetDefaultPageLayout(pageLayout, true);
publishingWeb.Update();
}
}
}
Here, I have set the Blank Web Part page as the default page layout to the SharePoint site. This way you can control the logic as your wish...
Read More...

Get default Page Layout for a SharePoint site

Sometimes when you are provisioning sites through web/site templates you might miss one thing that setting default page layout for the web. In SharePoint 2010 especially you have to face this issue when you try to browse to the page "Page layouts and Site Templates" from site settings page. If there is no default page layout then there are problems while creating new page as well. So, this could be a major issue in some special cases.

Sometimes you might get the error like "Data at the root level is invalid. Line 1, position 1" because of this.
So, we have to know is there any default page layout set for the site and below is the perfect console application solution for it.
        private static void GetDefaultPageLayout()
{
using (SPSite site = new SPSite("http://SP2010Site/"))
{
using (SPWeb web = site.OpenWeb())
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);

PageLayout pageLayout = publishingWeb.DefaultPageLayout;
Console.WriteLine(pageLayout.Name + "Url : " + pageLayout.ServerRelativeUrl);
}
}
}
So, this way you can trace easily some kind of problems which create problems to us. :)
Read More...

Copy users from one SharePoint group to another group

This is one of the question raises from many people who has to copy users from one SharePoint group to another group. There is no direct way you can directly copy users through browser. So, it could be problem to site owners and administrators to add all users again. How to solve these kind problems?

Here are some scenarios of why it is actually needed?
  1. There are so many SharePoint groups in the site and need to copy the users from one group to another group.
  2. Two sites needed same permissions and one site group permissions need to copy to another group.
So, from the ways I know below are the possibilities.

  1. Create a simple console application and  write logic to copy users.
  2. Use the simple option which is available through browser.
    1. Go to Site Settings of the site.
    2. Click on People and Groups.
    3. Go to the group from which you want to copy users.
    4. From the group page, select all  users and then from Actions Menu, choose "Email Users" as shown below.
    5. Once you selected "E-Mail Users" then your default email program (Ex: Outlook) will be open with all email addresses.
    6. Select all email addresses and copy them.
    7. Go to SharePoint site and then go to SharePoint group to which you want to add users.
    8. From the toolbar,  select "New" and then "Add Users". 
    9. From the add users page, paste all email addresses and then click "Check names" icon for validation.
    10. Click OK button to save the changes.
With the process above, we have successfully completed the copying of users from one group to another group. Love to hear any comments on it. 
    Read More...

    Permissions for document 'Move' operation in SharePoint

    This might not be a super thing to blog but very important point to note. Through code I have tried to move a document from one document to another document by using file.MoveTo() operation. It was working very fine when I tested as I am administrator in the dev environment. But, when I have given to QA for testing it was failing. I have tried so many combinations of giving different access to them and nothing worked. When I have given them either Owners or site collection administrator access it started working. So, I was not understanding of what was the permission level do they need?
    After tried different combinations of permission levels to them one matched and worked perfect. That was Contribute and Approve permission levels. So, for the logged in users who don't have both of these permission levels the code is failing for them and the  result file was not moving successful. [Another note is, I am using publishing site with auto approval of document in document library.]

    Code used:
    SPFile file = currentItem.File;
    file.MoveTo(filePath, true);
    For a document move operation the logged in user should need both Contributor and Approve permission levels for publishing web sites in SharePoint.

    I am thinking it is correct according to my analysis and research. Please let me know if something is wrong in this post or any better solutions. Read More...

    Move and Copy operations in SharePoint Lists

    Do not know how many of you aware of these important points.

    1. When you move a document/list item from one document library/list to another then the versioning will also be retained in that destination library/list.
    2. When you copy a document/list item from one document library/list to another then the versioning will not be copied to the destination library/list.
    3. When you move a document/list item from one document library/list to another then the metadata will not be copied. To do that you should have same columns in both libraries/lists and they should use same content type [Means they should have same schema].
    Read More...

    Upgrade SharePoint 2007 Visual Studio projects to 2010

    This will be very helpful for the scenarios where we have custom solutions developed in Visual Studio 2008 for SharePoint 2007 environment and upgraded 2007 site to SharePoint 2010 and now in SharePoint 2010 we like to do some changes to that custom solution files. Simply, we have a SharePoint 2007 site upgraded to SharePoint 2010 and then it has some custom solutions developed like web parts, solution packages, features etc. Now, we are in SharePoint 2010 environment and like to extend the custom web parts, features from the earlier version of SharePoint. So, we need some sort of support to migrate our SharePoint Visual Studio projects from Visual Studio 2008 to Visual Studio 2010 to deploy to SharePoint 2010. I believe you all are clear till this point.

    Get the tool here. http://archive.msdn.microsoft.com/VSeWSSImport/Release/ProjectReleases.aspx?ReleaseId=4183

    It is simple project and when you build it, you will get executable and installs template to Visual Studio. But, the only preliminary requirement here is, you have to install Visual Studio 2010 SDK to open project.

    Once everything is ready, you will see a new template named "Import VSeVSS project" under new project category. Here you go.....
    Read More...

    Check list exists in SharePoint site

    This is very generic issue all SharePoint developers face at initial stages. As there is no default method available in SharePoint API to check whether if list exists in the SharePoint site, everyone write the below code:
    SPList list = web.Lists["Task List"];
    If(list != null)
    {
    //Some code on list.
    }
    This is not correct to code like this. We all know generics and collections in c#. SPWeb.Lists is a collection and if you want to get one object from collection either we need to pass index or the key. If that didn’t find in the collection it gives us the exception. So, in our example if the Sharepoint site don’t have list named “Task List” then you will give run time exception in the line 1 itself. So, there is no point of checking whether list object is null. So, here is where many people stuck at. As Lists is plain collection object there is no other way of checking for the list exists in collection other than below.
    private static bool ListExists(SPWeb web, string listName)
    {
    try
    {
    SPList list = web.Lists[listName];
    }
    catch
    {
    return false;
    }
    return true;
    }
    I know what you are thinking [Is this solution right?]. Yes, unfortunately there is no other way. So, we have to use this to check whether list exists in a SharePoint site.
    Read More...

    How to go to SharePoint Webpart Maintenance page for any page

    This is one of the great tips we have in SharePoint. There are many scenarios why we need this. I had very tough time to migrate a SharePoint 2007 site to SharePoint 2010 site. What happened was,
    1. The other team deployed a custom web part 2 years ago.
    2. Used that web part on different pages in that site.
    3. They have taken the site template from the option "save site as template".
    4. After an year, they have removed  that web part from the site collection.
    5. But, with the same site template they have taken in the step #3, they created few sites in the same site collection after they removed the web part from environment.
    6. Remember, the site template still has the references to that custom web part. So, when I try to migrate it always fails..
    Sometimes it is very difficult to find what is causing the problem. The sites created were not published sites. So, I cannot go to Edit Properties of the page and go to web part maintenance page from there. As the default.aspx page is directly in the root of the site/web I do not have any other choice to go to web part maintenance page. After a long research I found from Google that the querystring ?contents=1 will do job for me.

    Resolution:
    In SharePoint, for any web part ASPX page if you append the querystring ?contents=1 then it automatically redirects to the web part maintenance page.

    Example: 
    For the SharePoint site page
    http://mossurl/default.aspx the web part maintenance page url is
    http://mossurl/default.aspx?contents=1
    Read More...

    Clear and then disable controls in infopath

    This is simple for reading, but difficult to implement in infopath forms. To disable controls we have to use “Conditional Formatting” option of a control. To clear content of a control then we have to use “Rules” option of a control. But, the sequence of execution of these two causes some problems. Take below scenario.
    I have a table and each row the first column contains a checkbox and all other 4 columns are having date field, textbox, drop down and date field respectively. Now, the logic should be this.
    1. The default state of checkbox is selected.
    2. When user enter some data in all other 4 fields and now he thought the row should not allowed to enter data then he deselect the checkbox. When user deselects then the first thing should happen is clear the content in all the 4 controls and then all controls should be disabled.
    3. When again user select the checkbox then the controls should be enabled.
    This is what to be happen and the first trail when I tried to implement I did below things.
    1. On all other 4 controls I added a rule that when checkbox selected state is false then set the current field to empty.
    2. And then I added a conditional formatting on them to disable when the checkbox state is unchecked.
    I did deploy them to SharePoint and when I tested, surprisingly they are not working as expected. The controls are going to disable state but not clearing content in them when I deselect the checkbox. And researched and found that the Rules are not executing. [Didn’t find the reason yet.] And then thought about for alternatives and came up with reverse way. That is, applying rule on the checkbox instead of other controls.
    Earlier, I have applied rules on the each and every individual control which needs to be cleared based on checkbox state – Which doesn’t work. Now, I have applied the same logic but applied rule on the checkbox [As there are 4 controls, 4 times I have added set field to empty] and which is working like charm.
    So the conclusion I want to tell to you is, when I apply conditional formatting and then rules something is causing problems in the sequence of execution. So, depends on what your control, rules needs to be executed apply the rules on that control only. That should work perfect. Read More...

    Delete event receiver from a SharePoint list

    In my previous post, we saw how we added an event receiver to a list. Now, we will see how to delete the existing event receiver on a list.
    private void DeleteEventReceiverFromAList(string siteUrl)
    {
    using (SPSite site = new SPSite(siteUrl))
    {
    using(SPWeb web = site.OpenWeb())
    {
    try
    {
    SPList list = web.Lists["myList"];
    if (list != null)
    {
    string className = "EventReceiverClass";
    string asmName = "EventReceiverAssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a865f0ecc234ea51";
    web.AllowUnsafeUpdates = true;

    int receivers = list.EventReceivers.Count;
    bool isAddedReceiverExist = false;
    bool isUpdatedReceiverExist = false;
    for (int i = 0; i < receivers; i++)
    {
    SPEventReceiverDefinition eventReceiver = list.EventReceivers[i];
    if (eventReceiver.Class == className && eventReceiver.Type == SPEventReceiverType.ItemAdded)
    {
    eventReceiver.Delete();
    break;
    }
    }
    }
    }
    catch { }
    finally
    {
    web.AllowUnsafeUpdates = false;
    }
    }
    }
    }
    In this code also, there is nothing to explain very detail. Please let me know if you have any questions.
    Read More...

    Add event receiver to a SharePoint list

    This is very generic and everyone knows how to add an event receiver. But, usually we attach the event receiver on a list template, site etc. This post deals with adding event receiver to a specific list.
    private void AddEventReceiverToAList(string siteUrl)
    {
    using (SPSite site = new SPSite(siteUrl))
    {
    using (SPWeb web = site.OpenWeb())
    {
    try
    {
    SPList list = web.Lists["myList"];
    if (list != null)
    {
    int receivers = list.EventReceivers.Count;
    string className = "EventReceiverClass";
    string asmName = "EventReceiverAssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a865f0ecc234ea51";
    web.AllowUnsafeUpdates = true;
    bool isAddedReceiverExist = false;
    for (int i = 0; i < receivers; i++)
    {
    SPEventReceiverDefinition eventReceiver = list.EventReceivers[i];
    if (eventReceiver.Class == className && eventReceiver.Type == SPEventReceiverType.ItemAdded)
    {
    isAddedReceiverExist = true;
    break;
    }
    }
    if (!isAddedReceiverExist)
    list.EventReceivers.Add(SPEventReceiverType.ItemAdded, asmName, className);
    }
    }
    catch { }
    finally
    {
    web.AllowUnsafeUpdates = false;
    }
    }
    }
    }
    This is very straight forward code and hope you got it. Read More...

    Hide content types from a SharePoint library through coding

    Please read the post here.

    Read More...

    Change content type order in NEW button of a SharePoint library

    This is continuation of my previous post. After you read that post you get clear understanding of how we added the content types to a library through coding. But, what if there is a requirement we need this content type order to be shown when I select the NEW button from the list tool bar or hide some content types? Then again we need some sort of code which does that for all existing lists as we cannot change manually if there are plenty of webs in a site.
    private void ChangeOrHideContentTypesInALibrary(SPList list)
    {
    list.ContentTypesEnabled = true;

    SPFolder folder = list.RootFolder;

    List<SPContentType> orderedContentTypes = new List<SPContentType>();
    foreach (SPContentType ct in folder.ContentTypeOrder)
    {
    if (ct.Name.Contains("ContentType1") || ct.Name.Contains("ContentType2"))
    orderedContentTypes.Add(ct);
    }

    folder.UniqueContentTypeOrder = orderedContentTypes;
    folder.Update();
    }

    If you observe the above code, then the variable orderedContentTypes is what having the content types of which we need to show in the NEW button of the list toolbar. In which order we add the content types to this variable, that order they will be added to the list and shown on the toolbar. And second thing is out of 3 content types available in the above logic we have added only two to the variable. So the third content type will be hidden from the toolbar. And the last two lines in the above function are to update the list with the latest content types order.

    Hope this gives you clear idea on how to order and hide content types on a list/library. Read More...

    Add content type to a SharePoint list or library through code

    In one of my SharePoint projects, there is a requirement like a SharePoint site has 140+ sub sites and each web has 2 lists which I need to update. There are 2 content types which are inheriting by each list and now I have to add another through coding. It is very difficult to go through all webs and each list in each web and manually add it. So, thought of writing a simple script which will loop through them and update them. So, here is the code I came up with.
    private void AddContentTypeToLibraries(string siteUrl)
    {
    List<SPContentType> contentTypes = new List<SPContentType>();
    using (SPSite site = new SPSite(siteUrl))
    {
    using (SPWeb web = site.OpenWeb())
    {
    contentTypes.Add(web.ContentTypes["ContentType1"]);
    contentTypes.Add(web.ContentTypes["ContentType2"]);
    contentTypes.Add(web.ContentTypes["ContentType3"]);
    }
    foreach (SPWeb web in site.AllWebs)
    {
    try
    {
    web.AllowUnsafeUpdates = true;

    foreach (SPList list in web.Lists)
    {
    if (!list.Title.Equals("MyList", StringComparison.InvariantCultureIgnoreCase))
    continue;

    for (int i = 0; i < contentTypes.Count; i++)
    {
    AddContentTypeToList(contentTypes[i], list);
    }
    }
    }
    catch { }
    finally
    {
    web.AllowUnsafeUpdates = false;
    web.Dispose();
    }
    }
    }
    }

    void AddContentTypeToList(SPContentType ct, SPList list)
    {
    if (list.ContentTypes[ct.Name] == null)
    {
    list.ContentTypes.Add(ct);
    list.Update();
    }
    }
    The first method is what we are looping through all webs and go to each list and try to add a content type. And the second method is before adding a content type to a list, we are checking whether the content type is already there or not for that list. So, we are checking for that condition and if find the content type is not already attached to the list then only we are adding to the list.

    Hope you understand the logic and how we need to implement it. Read More...

    UDCX files in Sharepoint Infopath and dynamic queries

    Confused? Can we use dynamic queries in the infopath and UDCX combination? UDCX are meant for not writing any code to get data from database and to show it up the retrieved data on the infopath form. They allow only STATIC queries. Just straight SQL or SPROC names  and parameters to it. But, I got a requirement where I need to pass some dynamic values to the query/SPROC at runtime and gets the data and loads the data on the form. Can I achieve that with same UDCX connections and same architecture?
    YES, There is a way to do this. The things to note here are:
    1. Using UDCX connections, we have saved all the connection data, query data and credentials data on a single file in SharePoint list/library.
    2. Query should be correct and executing without any issues [Otherwise infopath cannot download the resulted schema]. For example, you want to get the user by user name then you may created SPROC with name "GetUserByUserName" and in your UDCX file you give the query tag as "<udc:Query>EXEC "dbo.GetUserByUserName" 'DEFAULT'</udc:Query>". We know there is no record in database with the name "DEFAULT". But, this is what we have to give as default query. [This is what we will change in the c# code dynamically.]
    3. Read this connection, query in the infopath c# code.
    4. Change the query information in which way you want in code.
    5. Execute the query.
    6. Reset the UDCX connection information back to original.
    7. It will automatically refresh the control data depends on the latest result set after we executed from the C# logic.
    So, I believe you got complete picture of what we are going to do. This is very simple but difficult to get the idea. With this implementation I solved the big problems what I had.
    To execute the below code I am assuming there is a UDCX connection file available in a SharePoint library and your infopath form is allowing c# code.
    //Get the connection details by connection name 
    AdoQueryConnection adoConnection = (AdoQueryConnection)DataConnections["Get_User_Details"];
    if (adoConnection != null)
    {
    string orgCommand = adoConnection.Command; //To read original command
    int index = orgCommand.IndexOf("DEFAULT"); //Find where the keyword "DEFAULT" in the command string
    string SPROC = string.Empty;
    if (index > -1)
    {
    try
    {
    SPROC = orgCommand.Substring(0, index); //Get only the SPROC name.
    adoConnection.Command = string.Format(SPROC + userName + "'"); //Append user name to the query.
    adoConnection.Execute(); //Execute the final query. This is what the command which contains actual parameter value instead of DEFAULT string.
    }
    catch { }
    finally
    {
    adoConnection.Command = orgCommand; //Should not forget to write this. We have to do this.
    }
    }
    }
    Things to note:
    1. The connection name "Get_User_Details" is the connection name from infopath form [Managed Data Connections option].
    2. As we are reading from existing UDCX connection file, we are not hard-coded any of the connection strings or queries.
    3. userName is the string variable which holds the user name which comes at run time. You have to write some logic to get these in your code.
    4. Read the query and replace the dummy parameter values with the original values.
    5. Execute the connection.
    6. In finally block, we are resetting the command back to original.
    That's it!!! If you are binding this information to the textbox then you should do one final thing as shown in below figure.
    image
    The checkbox in above figure "Update this value when the result of formula is recalculated" and applies to only if you use the formula.

    We are done. The data now comes from database and passed the parameters to database dynamically, used UDCX connection file and did not hard-coded any of the connection, query information in code. Very clean right?

    Hope you understood it well and liked it. Read More...

    Publish Nintex workflow file to all sites and libraries using code

    Nintex workflows - They are easy to build workflows and customize. I used them in couple of projects and it supports many activities which we can use and build workflows according to requirements. But, this time I got a big project which has plenty of sub sites in a site collection. All sub sites are having the same site template and it has the same structure. Each sub sites has many libraries and out of them 8 are having workflow enabled.
    When I got a requirement to change something in workflow then I am in trouble like how to publish the new changed workflow to all libraries. Right now I have 148 sub sites. It means I have to publish the nintex workflow to 148 * 8  = 1184 libraries. Which is not at all possible with the manual upload process. So, the only way would be writing code to publish them automatically by running it.

    Few days back, I have written the post which describes the same without coding here.  But, that needs lots of prerequisites and will apply to only one site. The solution which I have written needs the updated nintex workflow file [.NWF] as input, web url and site url. It loops through all sites in the site collection and updates the each and every library with the updated nintex file successfully.

    Below is the code which does that for one site:
    private static void UpdateWokflowToOneSite()
    {
    string siteUrl = ConfigurationManager.AppSettings["SiteUrl"];
    List<string> listNames = new List<string>() { "List - 1", "List - 2", "List - 3", "List - 4", "List - 5"};
    using (SPSite site = new SPSite(siteUrl))
    {
    string webUrl = ConfigurationManager.AppSettings["WebUrl"];

    if (string.IsNullOrEmpty(webUrl))
    {
    webUrl = "/";
    }
    using (SPWeb web = site.OpenWeb(webUrl))
    {
    byte[] rawData = File.ReadAllBytes("UpdatedNintexWorkflow.nwf");
    NintexWorkflowWS.NintexWorkflowWS ws = new NintexWorkflowWS.NintexWorkflowWS();
    ws.Url = web.Url + "/_vti_bin/NintexWorkflow/workflow.asmx";
    ws.UseDefaultCredentials = true;

    int i = 1;
    foreach (string listName in listNames)
    {
    ws.PublishFromNWF(rawData, listName, string.Format("NintexWorkflow-{0}", i), false);
    i++;
    }
    }
    }
    }

    Below are the prerequisites for running above code.
    1. I have created a console application and writing code in it. So that I will get EXE as output and running it wherever needed [different servers by changing configuration file]. 
    2. We have to add the Nintex workflow web service reference to the project. So that we will call it and use it in code. The below line in the code is web service instantiation.
      NintexWorkflowWS.NintexWorkflowWS ws = new NintexWorkflowWS.NintexWorkflowWS();
    3.  The user who is logged in has the permissions needed to publish the nintex workflow. The administrator access are needed to run the above code.
    4. The NWF file location according to above code should be in the same location where EXE is present. By default it will be project location/bin/debug.
    5.  listNames is the variable which has all list/library names in the site to which we have to publish the workflow. In case if you want to publish to all list/libraries then replace the listNames in foreach with web.Lists.
    Now, the app.config entries are configurable. Below are the configuration changes needed.
    <appSettings>
    <add key="SiteUrl" value="http://sharepointsite"/>
    <add key="WebUrl" value="/"/>
    </appSettings>
    <system.serviceModel>
    <bindings />
    <client />
    </system.serviceModel>
    <applicationSettings>
    <DeployWorkflowNWF.Properties.Settings>
    <setting name="DeployWorkflowNWF_NintexWorkflowWS_NintexWorkflowWS"
    serializeAs="String">
    <value>http://sharepointsite/_vti_bin/NintexWorkflow/Workflow.asmx</value>
    </setting>
    </DeployWorkflowNWF.Properties.Settings>
    </applicationSettings>
    In this, change the configuration as needed and use it.

    You can use the same code loop through each and every web and publish it to all webs. I mean one more loop is enough to do that job as shown below.
    private static void UpdateWokflowToAllWebs()
    {
    string siteUrl = ConfigurationManager.AppSettings["SiteUrl"];
    List<string> listNames = new List<string>() { "List - 1", "List - 2", "List - 3", "List - 4", "List - 5"};
    using (SPSite site = new SPSite(siteUrl))
    {
    foreach(SPWeb web in site.AllWebs)
    {
    byte[] rawData = File.ReadAllBytes("UpdatedNintexWorkflow.nwf");
    NintexWorkflowWS.NintexWorkflowWS ws = new NintexWorkflowWS.NintexWorkflowWS();
    ws.Url = web.Url + "/_vti_bin/NintexWorkflow/workflow.asmx";
    ws.UseDefaultCredentials = true;

    int i = 1;
    foreach (string listName in listNames)
    {
    ws.PublishFromNWF(rawData, listName, string.Format("NintexWorkflow-{0}", i), false);
    i++;
    }
    }
    }
    }

    There we are done. Just run the EXE and it will update the workflow to each and every library in a web.

    Complete project is available for download here. Please let me know, if you need any more help. Read More...

    STSADM - Object reference not set to instance of an object

    I know this is the error which developers see most of the times. This is very basic error and it raises when we tried to access NULL reference object. But, What is if it comes while accessing STSADM? In SharePoint everyone knows the role of STSADM and the advantage of it. If you try to do some operation using STSADM tool and ends with the error "Object reference not set to instance of an object" then it is very difficult to trace as it is not giving us the enough information. But, with the experience, we get some ideas and solutions. Most of us know the resolution but I want to place everything what I know to my readers on this blog.

    Resolution:
    The user who runs the STSADM on the server should have access to the SharePoint Admin content database. If he don't have access, but he is administrator on server, has full access to central administration and farm administrator access then still no use. He should have access to the admin content database. Because whatever we do using STSADM then it is indirectly dealing with database only. So, user logged in should have access to database.

    This is one of the main thing which we need to remember in administration side. Hope you liked it and you remember it forever. And mainly this scenario will come on environment where the farm server setup and database server is different from SharePoint server. Read More...

    Operation is not valid due to the current state of the object when making changes to SPListItem object using elevated previliges

    This is known error to sharepoint developers that when try to update/delete a SharePoint list item using system account. Means using SPSecurity.RunWithElevatedPrivileges() method. I am not sure, why it is not allowing to update or delete a file in this code block. But, there is work around for it. You can still edit the item using elevated privileges. Here is a wonderful post, which helped me great and all credits to him.
    Make changes to SPListItem using elevated privileges
    I am really surprised by seeing the code in his article. It is completely unexpected and it is working great. I am really not believed when I saw the code very first time, but it is working.

    But, make sure you are disposing the objects correct. Hope this will help you too to fix the problem "Operation is not valid due to the current state of the object". Read More...
    Related Posts with Thumbnails
    GiF Pictures, Images and Photos