Wednesday, June 27, 2012

Access web.config in SharePoint timer job

In SharePoint customization we have the requirements to write custom code for web parts, timer jobs etc. In this post I want to tell you some interesting things in SharePoint. I have written some timer jobs to deploy into my SharePoint server to match some requirements or to solve some problems.
My requirement is, I want to access the web application or web site configuration [web.config] file in the SharePoint timer job. But, the limitations in SharePoint stops me to access the configuration files in timer job. Below are the problems I faced.
  • SharePoint timer job is running in different process named OWSTIMER.EXE.
  • SharePoint web application or site will run with the help of process W3WP.EXE.
  • So, the application configuration file is associated with the W3WP.EXE, so there is no way to access the web.config file in the owstimer.exe process at all. The context is completely different and out of domain. So, we need to call or access the web.config file explicitly in timer job. How to?
  • Remember, always C# is completely object oriented and you can access everything through objects.
  • Usually the timer job installed as a feature. And all the logic of the timer job will go inside the Execute() method. So, write below statements in that method and access the complete web.config file. Below is the example of accessing appsettings. 
SPWebApplication webApplication = this.Parent as SPWebApplication;
Configuration config = WebConfigurationManager.OpenWebConfiguration("/", webApplication.Name);
String appValue = config.AppSettings.Settings["appSettingKey"].Value;

WebConfigurationManager is the class which is in the namespace Systen.Web.Configuration. This way, you can access the config settings from a web.config of a SharePoint web site

SharePoint timer job and settings or configuration file

I got a question that what is the case when a SharePoint timer job needs a configuration file? Because, I really need the configuration settings for a timer job which I deployed. Because I got a requirement where I need to use the web service in a timer job and it needs the httpBindings and the endpoints. I can't place them in web.config of the web site as I can't access it here. But, I can access the web.config file as I discussed it in my previous post. I can get all the bindings and endpoints from web.config and create a c# bindngs object. And for the web service I passed the binding and that didn't solve the problem. Somehow, I got the below exception.
WSE012: The input was not a valid SOAP message because the following information is missing: action.
So, I started thinking in different ways and out of box. Below is the way how I approached towards the solution.
  • Everyone knows that all the timer job runs with the help of the OWSTIMER.EXE.
  • If you take a look at the console application, c# project and if you add the app.config file to the project then in your bin folder, you will see two files like if it is c# project then projectname.dll and projectname.dll.config and if it is console application then projectname.exe and projectname.exe.config.
  • So, what you understood from it? for dll or exe there is associated config file if that project contains app.config file.
  • What will happens when we use the dll or try to run the exe, the related config file also loads into memory and you can use the config file in the dll or exe.
  • There my thought starts and I want to repeat the same concept for the OWSTIMER.EXE too. 
  • Find the location of where OWSTIMER.EXE is reside in. Generally, the location is at "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\OWSTIMER.EXE". So, go to that location and create a file named OWSTIMER.EXE.CONFIG.
  • Open it in notepad and place all the settings code in it. Save it.
  • Now, it's time to restart the timer service. So, go to services and find SharePoint Timer Service. And restart it.
  • Now, run the timer service and you see everything is running successful. I mean all the settings will be loaded and run.
Note: Try to include all the settings in the config file within these tags.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

IIS 7 – Managed pipeline mode – Global.asax redirect not working

I installed Windows 7 and I really like it. I migrated all my applications from my old machine to new. And my old machine is running WS 2003 [iis 6] and new machine is Windows 7 [IIS 7]. In all applications everything ran successful except one. I implemented exception handling in my application. I have Global.asax page and in the Application_Error event, I log the exception details and redirecting the user to the error page. Whenever there is an exception in my application the page never redirect to the error page, it stays there in the same page with exception details on the screen.
The same code ran very successful on my old server and in Windows 7 it's not. I just started thinking what could be the issue. The analysis went in this way. Code not changed, DB not changed and the only part changed is the IIS. Windows 7 has IIS7. So, The problem would be either the isapi dll or the application pool. So, started researching on those and found interesting points.
In IIS 7, application pool has a separate feature named "Managed pipeline mode". This will tell the pool the pipeline mode. [which is of type sint32 in c# and the possible values for it are 0 and 1.]
  • 0 is managed pipeline runs in integration mode.
  • 1 is managed pipeline runs in classic or ISAPI mode. [IIS 6].
In Classic mode, managed application events are executed by using ISAPI. In Integrated mode, ASP.NET request processing integrates directly into the IIS 7 request-processing pipeline. Integrated mode enables you to configure managed modules for Web sites that are developed with unmanaged code.
So, to work your logic correct, go to your site and see under what application pool your site running. Now, go to that application pool, properties and change the pipeline mode to classic mode. Now, you see everything works fine and the page starts redirecting to error page when any exception in your application.
For more details: http://msdn.microsoft.com/en-us/library/microsoft.web.administration.managedpipelinemode.aspx

Open all anchor links in new window

How many ways are there to implement this?
1. Make all links in web page open in new window.
2. Only some part of the web page links will be opened in new window.

I have two options: Number 1,
Open all links on the web page in new window: Default HTML supports this.

Add this line in the <head> tag of your HTML:  <base target='_blank' />

If I make all links needs to be opened in new window then home link, navigation links, search everything will opened in new window and it will frustrate user that whatever you click on the link it will open in new window. Dozens of windows in user system if you click 10-12 links. Not a good idea.

Option 2: Only specific region anchor links open in new window. This looks promising and good. But, how to. For example, in my blog, I like to open the content links only in new window.
I have a parent for all content inside a div with id='content'. Now, my goal is to add some logic to open all links in new window which are under content only.
 <script type='text/javascript'>  
 //<![CDATA[      
window.onload = function ()
 {   
    var links = document.getElementById('content').getElementsByTagName('a');         for (var i = 0; i < links.length; i++) 
{           
 links[i].setAttribute('target', '_blank'); 
         }     
 }
  //]]> 
 </script>

If you are in Jquery , then this as,
$('#content a[href^="http://"]').attr("target", "_blank");

How to change the values of 'CreatedBy' and 'ModifiedBy' fields in SharePoint list

Each SharePoint list by default has these fields 'Created By' and 'Modified By'. The type of these fields is "Person or Group".
Whenever a new list item is added, the value of the 'CreatedBy' column is automatically set to the Login Name of current user.  
And whenever a list item is modified, the value of the 'ModifiedBy' column is automatically set to the Login Name of current user.   
 
Note: If you try to modify or update the 'CreatedBy and 'ModifiedBy' Fields, you may get the below error like   "Invalid data has been used to update the list item. The field you are trying to update may be read only". 

 
Now the question is "why the hell one needs to modify the values of these fields?” The answer can be found in the "Advanced Settings" section of a SharePoint list. One can see, there is a 'Edit own items' permission which means a user can edit all list items which he/she has created, that is very nice and useful feature. But the problem is that it is linked with the 'Created By' field. So if I will create a list item then my login name will be stored in the "Created By" field and only I can modify this list item. But if there is a requirement to modify this list item by some other user then how I can achieve that. To achieve this, one need to modify the value of "Created By" field and set it to the login name of that user. But How? 
I was just stuck with this problem, but finally found a solution. The values of 'Created By' and 'Modified By' fields can be modified programmatically. Here is a code snippet to achieve this: 

Method1:
using (SPSite site = new SPSite("SharepointSiteURL"))
{ 
  using (SPWeb web = site.OpenWeb())
  {
    web.AllowUnsafeUpdates = true;
    SPList list = web.Lists["ListName"];
    foreach (SPListItem item in list.Items)
    {
      SPUser user = web.EnsureUser("User'sLoginName");
      //In the "Created By" and " Modified By" fields values are stored in this format      "ID;#LoginName", so create the same format.
 
      string userValue = user.ID + ";#" + user.Name;
      item["Author"] = userValue ;
       //InternalName of "Created By" field is "Author"
      item["Editor"]=userValue ; 
      //InternalName of "Modified By" field is "Editor"
      item.Update(); 
    }
    list.Update();
}
Method2:

using (SPSite site = new SPSite("SharepointSiteURL"))
{ 
  using (SPWeb web = site.OpenWeb())
  {
      web.AllowUnsafeUpdates = true;
      SPList list = web.Lists["ListName"];
      SPListitemCollection itemcollection=list.items;
      foreach (SPListItem item in itemcollection)
      {
         SPFieldUserValue user1=new SPFieldUserValue(web, web.CurrentUser.ID,
                                      web.CurrentUser.LoginName);
        Listitem[“Author”]=user1;
        Listitem[“Editor”]=user1;
     }
  }
}

Tuesday, June 26, 2012

Eventreceiver Deploying Issue in Sharepoint 2010

Error occurred in deployment step 'Activate Features': Operation is not valid due to the current state of the object in Event Reciever

Cause:Define the variables Globally so remove the global variables then Deployment will not interrupt.

Wednesday, May 2, 2012

SharePoint Solution File L ocations Inside the SharePoint Root Directory

Path Relative to SharePoint Root                      Directory Template File Types



/ISAPI                                                                                                                               Web Services (.svc, .ashx, .asmx)


/Resources                                                                                                                        Resource files (.resx)

/TEMPLATE/ADMIN                                                                                                          Application pages used exclusively in Central Administration

/TEMPLATE/CONTROLTEMPLATES                                                                                    ASP.NET User Controls (.ascx)

/TEMPLATE/FEATURES                                                                                                      Feature definition files (.xml)

/TEMPLATE/IMAGES                                                                                                         Images (.gif, .jpg, and .png)

/TEMPLATE/LAYOUTS                                                                                                       Application pages (.aspx)

/TEMPLATE/LAYOUTS/1033/STYLES                                                                                  CSS Files (.css)

/TEMPLATE/LAYOUTS/ClientBin                                                                                        Silverlight components (.xap)

/TEMPLATE/SiteTemplates                                                                                                Site Definition files (onet.xml)

/TEMPLATE/XML                                                                                                              Custom field type definition files (fdltype*.xml)