Showing posts with label Sharepoint 2010. Show all posts
Showing posts with label Sharepoint 2010. Show all posts

Wednesday, October 3, 2012

SharePoint server is not installed on this computer

Share/Save/Bookmark

Are you victim of this error? then, you must be trying to use SharePoint 2010 templates in visual studio 2010  on the system that does not have Sharepoint installed.

So how to make it work with out installing the SharePoint server on local machine? After googling around, the hack that i found is to export the registry from SharePoint 2010 machine and import it to the machine where you are running visual studio.
Follow the below detailed steps,


  • Run regedit in command prompt on Sharepoint server
  • Navigate to the path [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0]
  • Copy the whole 14 hive registry by exporting it.(File->Export)
  • Open the registry in local machine where you are trying to develop sharepoint solutions using VS2010
  • Export the copied registry (File->Import)
The last step is to copy the SharePoint dlls at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI from sharepoint server to local machine.
Copy the necessary sharepoint dlls to GAC or use Gacutil to do.
Now after restarting VS you must be able to create projects using sharepoint templates. 
This way i could successfully develop sharepoint solution using  VS2010 when sharepoint is on a different system(in  my case sharepoint online) though debugging is not possible.

Subscribe

Saturday, August 18, 2012

Dispose RootWeb,ParentWeb,limitedwebpartmanger?

Share/Save/Bookmark

we all know that disposing SPSite/SPWeb objects is the best practice that will avoid any memory leaks. If you know the first point then you should also know when to dipose?

Objects accessed from the SPContext or properties(feature) do not need to be explicitly disposed but where as instantiated as below need to be.

SPSite site = new SPSite("http://abc.com");

So just wrap the above line of code with using that will automatically dispose the SPSite object when its out of scope.

Using(SPSite site = new SPSite("http://abc.com"))
{
      .....
}

There are some very special cases where we get confused, which I gonna cover here,

SPWeb web = site.RootWeb/ParentWeb
                        or
SPWeb web = SPcontext.Current.Site.RootWeb/ParentWeb

Should the web object be disposed in the above scenario?Certainly NOT, as these objects are disposed implicitly when site object is disposed i.e wrapped "using" when it is instantiated and in other case by sharepoint  when it(spsite) is from SPContext.


That being said how about SPWeb from SPContext.Current.Site.OpenWeb() ?
From the reflector it can be seen that a new instance of SPWeb is created when OpenWeb is called, irrespective of the way SPSite is instantiated.So in the code SPWeb should be disposed always explicitly.

Also, SPLimitedWebPartManager implements IDisposable which means it should be disposed when ever used.
we always follow the below practice when it comes to SPLimitedWebPartManager


using (SPWeb web = site.OpenWeb()) 
{
using (SPLimitedWebPartManager webPartManager = web.GetLimitedWebPartManager(url, scope))
            {
                
                    webPartManager.AddWebPart(mstrReport, entry.Key.ToString(), 0);
                     webPartManager.SaveChanges(mstrReport);
                
            }
}


I had a doubt if SPlimiedWebPartManager should be disposed when it is read from SPContext as below,

SPContext.Current.Web.GetLimitedWebPartManger(..)

So quickly i opened the reflector to see what is happening in the background, then i realized that it should be disposed and along with it the property, web.
Here is the snippet from reflector.


internal SPLimitedWebPartManager GetLimitedWebPartManagerInternal(Uri pageUrl, int pageVersion, PageView requestedView, bool forRender, bool includeHidden)
{
    if (null == pageUrl)
    {
        throw new ArgumentNullException("pageUrl");
    }
    if (!pageUrl.IsAbsoluteUri)
    {
        throw new ArgumentException(WebPartPageResource.GetString("AbsoluteUriRequired"), "pageUrl");
    }
    this.EnsureAspx(this.GetWebRelativeUrlFromUrl(pageUrl.ToString(), false, true));
    SPWeb web = this.Site.OpenWeb(); // THIS  WEB IS NEVER DISPOSED HERE
    web.IsOwnedByWebPartManager = true;
    SPWebPartManager manager = null;
    try
    {
        long num;
        if (this.AllowUnsafeUpdates)
        {
            web.AllowUnsafeUpdates = this.AllowUnsafeUpdates;
        }
        manager = web.GetWebPartManagerInternal(pageUrl, pageVersion, requestedView, forRender, includeHidden, out num);
    }
    catch
    {
        web.Dispose();
        throw;
    }
    if (manager != null)
    {
        return manager.LimitedWebPartManager;
    }
    return null;
}


The above web instance created by sharepoint in the method is not disposed. So i checked if it is doing it in SPLimitedWebPartManager.Dipose()



public void Dispose()
{
    if (!this.m_disposed)
    {
        if (this.m_manager != null)
        {
            this.m_manager.Dispose();
        }
        this.m_webParts = null;
        this.m_webPartDefs = null;
        this.m_manager = null;
        this.m_disposed = true;
    }
}


Ah, Its not doing even here which clearly shows that it should be explicitly disposed by the developers.
So best practice gonna be as below.


using (SPWeb web = site.OpenWeb()) // SPWeb web = SPContext.Current.Web
{
using (SPLimitedWebPartManager webPartManager = web.GetLimitedWebPartManager(url, scope))
            {
                 try 
                   {
                    webPartManager.AddWebPart(mstrReport, entry.Key.ToString(), 0);
                     webPartManager.SaveChanges(mstrReport);
                   }
                finally
                  {
                   // this web is created by sharepoint but not the above one
                      webPartManager.Web.Dispose(). 
                  }
                
            }
}




 Subscribe

Sunday, May 6, 2012

Read SharePoint Service using JQuery

Share/Save/Bookmark


I had spent a day to know that soap response can be read at the event complete but not success.
In success event soapresponse(data.responseXML) is always empty. I'm not sure if its a sepcial case with soap.

Below function of Jquery retrieves the SocialTag count of a specific URL from all users.
Complete event triggers all the time after the service call resulting in success or error. So i used a flag based on which i can get to know if the service call is success or error.

function GetLikeCountFromService(domId, url) {

var tagName = "I like it";
var queryStatus = true;


var soapEnv =
"<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>\
<soap:Body> \
<GetTagTermsOnUrl xmlns='http://microsoft.com/webservices/SharePointPortalServer/SocialDataService'>\
<url>" + url + "</url>\
<maximumItemsToReturn>'100</maximumItemsToReturn> \
</GetTagTermsOnUrl> \
</soap:Body> \
</soap:Envelope>";

$.ajax({
url: '/_vti_bin/socialdataservice.asmx',
type: 'POST',
dataType: "xml",
data: soapEnv,
complete: function (data) {

//process only if the query is success
if (queryStatus) {
var likeCount = 0;
$(data.responseXML).find("SocialTermDetail").each(function () {
var term = $(this).find("Term").find("Name").text();
//alert($(this).find("Term").find("Name").text());
if (term == tagName) {
likeCount = $(this).find("Count").text();
// set the like count
$(domId).text(likeCount);
return;
}
});
,

error: function (all, textStatus, errorThrown) { queryStatus = false; alert(errorThrown); },
contentType: "text/xml; charset=\"utf-8\""
});
}



JQuery made life easy with flexible API. I have implemented another function similar to it that will like a URL, in sharepoint terms tagging a url with "I Like It". As a combination this will work as similar to the Social Like feature in Facebook.

Subscribe

Monday, April 16, 2012

Access SocialTerms or Tags in custom timer job

Share/Save/Bookmark


Though we thought this could make implementing the functionality very easy, it went through with a lot of research and lessons learnt.

So, what’s the issue?

When accessing the tags/terms(GetTerms) from SocialTagManager it always throw an error “Microsoft.Office.Server.UserProfiles.UserNotFoundException: An error was encountered while retrieving the user profile”. With a common sense we can see that timer jobs run in a different contextual process(owstimer.exe) which is by default configured to be run by networkservice account. So I thought maybe service accounts did not have user profiles and that’s why it threw error.
Now, I navigated to CA and tried to add user profile for networkservice account which threw another error. The whole point that I understand here is service accounts(system,networkservice) cannot have user profiles but only for domain accounts. [Lesson 0]

My common sense strikes again and asks why does it need a userprofile? I just asked to get all tags for a url on which service account cannot be used to Tag.
It’s time to review what MS has done. So I pulled the source revealer, Reflector from the ware house and found the below code in SocialTagManager class


public SocialTerm[] GetTerms(Uri url, int maximumItemsToReturn, SocialItemPrivacy socialItemPrivacy)

{
SocialTerm[] termArray2;
if (null == url)
{
throw new ArgumentNullException("url");
}

if ((maximumItemsToReturn < 0) || (maximumItemsToReturn > 0x3e8))
{
throw new ArgumentOutOfRangeException("maximumItemsToReturn");
}

bool flag = socialItemPrivacy == SocialItemPrivacy.IncludeAllPrivateData;

bool flag2 = socialItemPrivacy == SocialItemPrivacy.IncludeMyPrivateData;

if (flag && !base.IsSocialAdmin)
{
throw new UnauthorizedAccessException();
}

url = AlternateAccessMapping.GetSerializedUrl(url);
using (SqlCommand command = new SqlCommand("dbo.proc_SocialTags_GetTermsForUrl")) // Procedure to get all terms for url from DB
{

command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@includePrivate", SqlDbType.Bit).Value = flag;
if (flag2)
{
command.Parameters.Add("@viewer_user_recordID", SqlDbType.BigInt).Value = base.GetCurrentUserProfileRecordId(); // Incudes current user private data
}

…..

….

}

What we can infer from the code is that, when a user attempts to read social data his/her private data(tags/notes) is included the reason why GetTerms(url) is looking for userprofile of the user(networkservice) running the code - [Lesson1]. Found the root cause but what is the solution?

Quickly impersonation came to the mind, and I passed the token of my domain account while instantiating SPSIte object, still no luck but the same error. Again reflecting the DLL’ s I found the below from UserProfiles.UserProfileGlobal class.

[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal
internal static string GetCurrentUserName()
{

string user = string.Empty;
HttpContext current = HttpContext.Current; //GOTCHA 1

if (current != null)
{
SPUtility.EnsureAuthentication(SPControl.GetContextWeb(current));

user = current.User.Identity.Name;
if (!current.User.Identity.IsAuthenticated)
{
throw new UnauthorizedAccessException(StringResourceManager.GetString("Exception_UserProfileGlobal_cs35"));
}
}

if ((user == null) || (user.Trim().Length == 0))
{
user = WindowsIdentity.GetCurrent().Name.ToLower(CultureInfo.InvariantCulture); //GOTCHA 2
}

if (!IsWindowsAuth())
{
if (!IsClaimsAuth())
{
user = SPUtility.FormatAccountName(user);
}

else
{
if (!SPClaimProviderManager.IsEncodedClaim(user))
{
user = SPUtility.FormatAccountName(ClaimsProviderConstants.strClaimsAuthMembershipProviderName, user);
}
user = EnsureWindowsLegacyAndClaimsEquivalence(user);
}
}

if (string.IsNullOrEmpty(user))
{
throw new UserProfileException(StringResourceManager.GetString("Exception_UserProfileGlobal_cs36"));
}
return user;
}

Ah, so that is how it’s getting the current user, which has always been the windows identity(code line labeled, GOTCHA 2) responsible for running the OWSTIMER process because HttpContext is always null in this case. As HttPContext is null, the impersonation code introduced by us will never gonna work. – [Lesson 2]
Since then I hated networkService and the object model for SocialData, being said that I could not wind this up concluding it’s not possible.

With no other option left, I have configured(SharePoint 2010 Timer->properties->logon Tab) my domain account(layman terms, account that has sharepoint userprofile) to run the OWSTIMER.EXE under services.msc. Restart timer service and IIS.

With no surprise, an error again but a new one, this time it threw the below error while instantiating SocailTagManager itself.

“Object reference could not be found at - at Microsoft.Office.Server.Administration.UserProfileApplicationProxy.get_ApplicationProperties().”

Even after using reflector, I could not find a clue but after gooogling, I came to know that I missed restarting the application service. [Lesson 3]

Now the error makes some sense for me. With an excitement I restarted User Profile Application service(CA->Manage Services on Server) and BRAVO, I nailed all the errors and it’s working. If you still did not get it working, you may need to try changing the account(in inetmgr) that runs the application pool responsible for User profile service application.

Though I found it working, I’m not sure on the best practice or the impact of configuring a non-service account to run the services.

UPDATE : Lately i learnt that socialterms can be accessed from timer job/console application(where httpcontext is null by default) by populating the context explicitly as below.

HttpRequest request = new HttpRequest("", http://teamsite, "");

HttpContext.Current = new HttpContext(request,
new HttpResponse(new StringWriter(CultureInfo.CurrentCulture)));
HttpContext.Current.Items["HttpHandlerSPWeb"] = web;

WindowsIdentity wi = WindowsIdentity.GetCurrent();
typeof(WindowsIdentity).GetField("m_name", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(wi, user.LoginName);
HttpContext.Current.User = new GenericPrincipal(wi, new string[0]);
WindowsIdentity wi2 = WindowsIdentity.GetCurrent();

SocialCommentManager socialCommentManager = new SocialCommentManager(
SPServiceContext.GetContext(HttpContext.Current));

Though i have not tried hands on, i see the above solution promising. Actual reference can be found here.
I appreciate MS for leaving such puzzles in the code ;) …LOL


Subscribe

Monday, April 2, 2012

Close Shared WebPart Programmatically

Share/Save/Bookmark


These days i have been banging my head between personalized and shared mode of the publishing page.
Well, every publishing page has a shared mode(PageView=Shared) and personalize mode(PageView=Personal). Deleting a webpart from the mode in which it is added is possible but cross deletion is not possible. What i mean is deleting a webpart, added in shared mode from personalized mode .
SharePoint only allows to close such webparts, so how do we that operation programmatic?
Somehow SPLimitedWebPartManager did not work for me in doing this but definitely SPWebPartManager does the trick.

SPWebPartManager spwebPartManager = SPWebPartManager.GetCurrentWebPartManager(this.Page);
SPContext.Current.Web.AllowUnsafeUpdates = true;
               
if (currentWebPart.IsShared == false)
      spwebPartManager.DeleteWebPart(currentWebPart);
else if (currentWebPart.IsShared == true)
      spwebPartManager.CloseWebPart(currentWebPart);


SPContext.Current.Web.AllowUnsafeUpdates = false;


Subscribe

Sunday, April 1, 2012

Overriding context of AverageRating Control of SharePoint 2010

Share/Save/Bookmark

SharePoint uses AverageRatingControl to display the rating(5 star) for any item. So i have used the same control to display for all the list items on a home page, but the tricky thing is that the control takes the context of the current page but not the list item it is supposed to represent. To do that i have to follow the below code to set or override the context of the item.


HttpContext context = HttpContext.Current;
SPServiceContext serviceContext = SPServiceContext.GetContext(SPServiceApplicationProxyGroup.Default, SPSiteSubscriptionIdentifier.Default);
averageRatingControl.ItemContext = = SPContext.GetContext(context, report.ItemId, listID, SPContext.Current.Web);

  Subscribe

Saturday, September 3, 2011

Remove format when copy paste in rich text editor

Share/Save/Bookmark

How do i avoid the formatting that comes along when i copy paste content from a site or word document to the Rich Text Editor (RTE) field in sharepoint? Ofcourse RTE already have an option Clear Formatting that can be used to clear after pasting the content,, but i do not want the format to be copied at first. So after digging into SP.UI.RTE.js and googling i have come up with a small script that will not paste the markup but only text.


    //Disable the RTE paste option. Restricts to "Paste Plain Text"
    function disableMarkupPasteForRTE()
    {
     Type.registerNamespace("RTE");
     if (RTE)
     {
      if(RTE.RichTextEditor != null)
      {
       RTE.RichTextEditor.paste = function() { RTE.Cursor.paste(true); }
       // Handle Ctrl+V short cut options in rich text editor
       RTE.Cursor.$3C_0 = true;
      }
     }
    }

I used the below standard sharepoint javascript function that will run the above or any javascript function on load of page.

    _spBodyOnLoadFunctionNames.push("disableMarkupPasteForRTE");


 Subscribe

Saturday, March 19, 2011

Webpart Connections in Sharepoint 2010 PageLayouts

Share/Save/Bookmark
Days, come back to work with sharepoint designer 2010 developing pagelayouts,
In the process of developing the page layouts it is observed that the webparts that are placed inside
the tags do not work after a page is created based on the pagelayout though the webpart connection is already set.
So i have to move the webparts outside of UIVersionContent tags to have the connections work in pages.


Are you wondering what is UIVersion? This is something new in 2010 w.r.t visual design, which indicates that the elements(part of pages) that you are developing is meant to be compatible for 2007/2010 by setting the attribute UIVersion=3/4


 Subscribe

Sunday, February 20, 2011

Access Page field in Dataform webpart

Share/Save/Bookmark

It’s the first time i got a chance to work on the so called, Swiss knife of SharePoint "Dataform" webpart .
I have a requirement to pull the data (different sitecollection) using dataform webpart
and filter the data based on the field value of the page(created based on page layout) where the webpart is placed on.

As it is cross site querying, I have to add a new SOAP datasource and configure it to dataform webpart. I could pull the data,
so how to access the page field value inside the dataform webpart xsl?
ParameterBinding is the solution for it.
It allows you to declare the external parameters that can be accessed by dataform webpart.

So how do we get this work??
  
Create datasource :

There are many feeds lying out there on web that would help you to create a soap datasource and pull data using dataform webpart with the help of Sharepoint Designer.

Define ID attribute:

Make sure ID attributes are set for the page fields that you want to access in dataform webpart. For example i want to access a look up field that is part of a pagelayout which is defined as

ParameterBinding:

In Sharepoint designer 2010 click on the dataform webpart to see the its properties/settings
on the ribbon. Click on parameters on options tab as shown below


Name the parameter "lookupFieldParam" that should be binded to the pagefield control
holding the id PageFieldSrc as selected in the screen. Default value for this new param can also be selected.



After you click on ok, designer adds the necessary param definition xsl tags to the dataform webpart. The place you should care about to have it is under

<parameterbindings>
 ....
<ParameterBinding Name="lookupFieldParam"  Location="Control(PageFieldSrc,ItemFieldValue)" DefaultValue="ABC" />
</parameterbindings>

Now it’s time to test our efforts...

Add the below xsl tag under row template and create a page based on that pagelayout to see if the parameter is fetching the value.

<xsl:value-of select="$lookupFieldParam" />
 Note $ reference here.

So now we have page field value in dataform webpart, how to use this to filter the data in dataform webpart will be drafted in my next version of this post.

 Subscribe

Monday, December 13, 2010

Migrate Sharepoint 2010 Metadata or Taxonomy

Share/Save/Bookmark

Below is the simple code that migrates metadata or taxonomy from one store(metadata service) to other on same farm.


public class TaxonomyUtility
    {
        public void MigrateTaxonomy(SPSite sourceSite,SPSite destinationSite,string srctermstoreName, string destermStoreName string termGroup, string termSet)
        {
            TaxonomySession srcTSession = new TaxonomySession(sourceSite);
            TaxonomySession desTSession = new TaxonomySession(destinationSite);
            TermStore srcTermStore = srcTSession.TermStores[srctermstoreName];
            TermStore desTermStore = desTSession.TermStores[destermStoreName];

            Group desGroup;
            TermSet desTermSet;
            Term desTerm;
            foreach (Group g in srcTermStore.Groups)
            {
                // Carry permisssions
                //foreach (SPAce groupManager in g.GroupManagers)
                //{
                //}

                desGroup = desTermStore.CreateGroup(g.Name);
                foreach (TermSet tSet in g.TermSets)
                {
                    desTermSet = desGroup.CreateTermSet(tSet.Name, 1033);
                    foreach (Term t in tSet.Terms)
                    {
                        desTerm = desTermSet.CreateTerm(t.Name,1033);
                        getLabels(t,desTerm);
                        getTermsRecursive(t,desTerm);
                    }
                }
            }
            desTermStore.CommitAll();
        }

        public void getTermsRecursive(Term srcTerm, Term destTerm)
        {

            if (srcTerm.Terms.Count > 0)
            {
                foreach (Term sTerm in srcTerm.Terms)
                {
                    destTerm = destTerm.CreateTerm(sTerm.Name, 1033, sTerm.Id);
                    getLabels(sTerm,destTerm);
                    getTermsRecursive(sTerm, destTerm);
                }
            }
            else
            {
                return;
            }
        }

        public void getLabels(Term srcTerm,Term desTerm)
        {
            foreach (Label l in srcTerm.Labels)
            {
                desTerm.CreateLabel(l.Value, 1033, l.IsDefaultForLanguage);
            }
        }
    }
}

Voila ...u did it ;-)
Other ways of migrating metadata term store in sharepoint 2010 and their limitations are discussed here.

  Subscribe

Thursday, November 4, 2010

Programmatically read MetaData Store

Share/Save/Bookmark

Here is the code that you can reuse to read the complete managed metadata store or taxonomy in SharePoint for a specific site collection.
Below code writes the metadata to a xml file following a very basic schema also presents it on console in a formatted style.

For basic understanding, the classes or the taxonomy hierarchy(new in SharePoint) is like below

Taxonomy Session 
            |
    Term Store
            |
       Group
            |
      TermSet
            |
        Term

Microsoft.SharePoint.Taxonomy is the dll that's used here to play around with SharePoint taxonomies.


namespace MetaDataReader
{
    class Program
    {
        static string fmt = "---------"; // used for formatting the hierarchy while displaying on console
        static XmlTextWriter writer = new XmlTextWriter("metadataStore.xml", null);
        public static void Main(string[] args)
        {
            try
            {
                SPSite site = new SPSite("http://mywebappurl");
                TaxonomySession txSesssion = new TaxonomySession(site);
                writer.WriteStartDocument();
                foreach (TermStore store in txSesssion.TermStores)
                {
                    Console.WriteLine("TermSTORE : " + store.Name);
                    writer.WriteStartElement("TermStore");
                    writer.WriteStartElement("Name");
                    writer.WriteString(store.Name);
                    writer.WriteEndElement();
                  
                    foreach (Group g in store.Groups)
                    {
                        Console.WriteLine("...TermGROUP : " + g.Name);
                        writer.WriteStartElement("TermGroup");

                        writer.WriteStartElement("Name");
                        writer.WriteString(g.Name);
                        writer.WriteEndElement();

                        foreach (TermSet tSet in g.TermSets)
                        {
                            Console.WriteLine("......TermSET : " + tSet.Name);
                            writer.WriteStartElement("TermSet");

                            writer.WriteStartElement("Name");
                            writer.WriteString(tSet.Name);
                            writer.WriteEndElement();

                            foreach (Term t in tSet.Terms)
                            {
                                Console.WriteLine(fmt + "TERM :" + t.Name);
                                writer.WriteStartElement("Term");

                                writer.WriteStartElement("Name");
                                writer.WriteString(t.Name);
                                writer.WriteEndElement();
                                getTermsRecursive(t);
                                writer.WriteEndElement();
                            }
                            writer.WriteEndElement();
                        }
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                }
                writer.WriteEndDocument();
                writer.Close();
            }
            catch (Exception ex)
            {//Do not swallow ;}
        }

        public static void getTermsRecursive(Term t)
        {
            if (t.Terms.Count > 0)
            {
                fmt += "---";
                foreach (Term sTerm in t.Terms)
                {
                    Console.WriteLine(fmt + "TERM :" + sTerm.Name );
                    writer.WriteStartElement("Term");
                    writer.WriteStartElement("Name");
                    writer.WriteString(sTerm.Name);
                    writer.WriteEndElement();
                  
                    getTermsRecursive(sTerm);
                    writer.WriteEndElement();
                }
            }
            else
            {
                fmt.Remove(fmt.Length-3);
                return;
            }
        }
    }
}



 Subscribe

Monday, October 4, 2010

Configure BCS in Sharepoint 2010

Share/Save/Bookmark

Lets get started with BCS in sharepoint 2010 with a small demo thats compiled as step by step instruction:

1. Open any MOSS site using Sharepoint Designer 2010

2. Select External content Types on left menu under Site Objects



3. Click on External Content Type, (seen on ribbon) to create a new one

4. Provide name and select  click here to discover external system where the data is residing to add external data source system





5. Click on Add connection to add a data source. Here our data source type is SQL server as the external data is a table in SQL server.





6. Provide server properties to connect to sql server



7. After successfully connecting to the new external data source through the data connection, add operations(read,insert,update,delete) by right clicking on the table(here EMP) that needs to be pulled through BCS.

8. Create New Read List Operation


9. Run through the wizard where operation parameters (Filter/Return) can be specified. Note the errors and warnings that are self explanatory for which, properties of each element can be changed accordingly to resolve them.



10.   For any external content type to be of use, it should at least have the read list and read item operations created. The same information can be seen in the External Content Type Operations panel.



11.   Now Create Read Item operation(follow steps 8 & 9)

12.   Save

13.   Open CentralAdmin to see the new External Content Type that is created




14.   Click on Set Object Permissions or Set Metadata Store Permissions to provide relevant permissions to the users who ever should access the external data pulled out by the external List, created based on the External content type. Note that missing this step would give Access Denied to Business Connectivity Services when tried to view external list. 



15.   Create External List using designer to see the output that we are waiting for. External list can also be created through the site.




  16.   Navigate to the External list (here DemoExCTList) in the site and here is the external data in sharepoint.





  Subscribe