September 2007 - Posts

I have often bound GridViews to my own custom objects. However today, I needed to bind a GridView to a List<string>. I needed to customize the columns a bit and I soon realized I did not know what to specify as a DataField. I tried Item and just blank but that just did not work. After some quick searching, I found the answer I needed in some community content on the GridView documentation on MSDN. The answer is an explanation point (!). Check out the example below.

<asp:GridView id="MyGridView" runat="server">
  <Columns>
       <asp:BoundField id="!" HeaderText="My Primitive" />
  </Columns>
</asp:GridView>

That is all there is to it. It doesn't seem to be a very well know fact, so I hope this helps someone.

Filed under:

I have been doing a lot of work with Enterprise Search again lately and in my testing process, I thought I would share some helpful information on the process. Today, I am working with managed properties. Managed Properties are properties in Enterprise Search that can be searched upon in custom queries or returned and displayed with the CoreResultsWebPart. A lot of this is document ok, but I thought it was worth reiterating.

If your source is the BDC, the thing I will reiterate again is to start small. Don't import the entire table at first just import the first small subset of rows. This is because as you are trying to get search to pick up your propeties, it is a lot easier to do it with small crawls. After your first successful crawl, Enterprise Search will list all of the columns its crawled as Crawled Properties. By default, anything that is a text field is searchable by doing a default search from a typical search. However, you may want to do a search and only search across certain properties instead of everything. To make this happen, you create Managed Properties. You simply create one and map it to the crawled properties of the entities you want to search. For example, if you want to search by state, you can create a property of that name and map it to the corresponding state crawled properties of all your entities.

After you set up a Managed Property, you must do another full crawl. If you don't, you will never be able to do queries based on the new managed properties you created. After that, you can start working on an advanced search page to seach these properties or you can query on them using the keyword syntax like below.

ManagedProperty:"MyKeyword"

For example, if I wanted to search for everything that had the state of texas, I would do the following.

State:"Texas"

You can also combine multiple keyword queries. Again this is all in the help, but this is how I test and make sure my managed properties are working.

State:"Texas" LastName:"Smith"

Hopefully, this will aid you the next time you are setting up Enterprise Search.

So you just finished setting up Enterprise Search in your development environment and now your PM wants you to move it to test. You set up content sources, managed properties, scopes, etc. Hmm, you just need to click on the handy Copy My Search Settings to Another Server button. Oh wait, that's right there isn't one. What are your options? Well you did document everything you configured so you can just manually configure it by hand on another server. That should only take a day or two. Another option is backing up the SSP and then doing a restore. This obviously has other implications.

You would think stsadm could do something for you here but alas no. There is a solution though. It's a project on CodePlex called Sharepoint Shared Services Search Provider Property Creation (or SSSPPC). Available in binary and source forms, this tool makes it pretty easy to get your Content Sources, Scopes, and Managed Properties created. It will also do Crawled Properties if you are feeling brave. This command line utility simply exports your search settings and stores them in XML format. These can then be easily imported on another server. If you are searching with the Business Data Catalog, your first need to import all of your BDC schemas. Then you can import your content sources. At this point the product recommends doing a full crawl. This has to be done before trying to import managed properties, becuase if the crawled properties do not exist prior to importing the managed properties, the process will fail. You also can just import the crawled properties first, but I don't think this path is fully supported yet. After that you can import your search scopes.

So far after using the tool, the only issue I have ran into is that it did not always bind the content source to the BDC instance, but this might have been an issue with my system.

SSSPPC

Once again, the most seemingly simple task with SharePoint has proved to be incredibly difficult. Continuing with my commitment to post the most information possible about SharePoint oddities, here is today's post. My goal today, I thought was simple. I wanted to use Enterprise Library to log errors in the application. I knew I would have to apply some code access security but I was prepared for that. I had no idea what a chore it was going to be.

I created a wrapper library for the Enterprise Library logging. I created a manifest file and I made sure to give explicit permission to the following DLLs Microsoft.Practices.EnterpriseLibrary.Common, Microsoft.Practices.EnterpriseLibrary.Data, Microsoft.Practices.EnterpriseLibrary.Logging, Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll, Microsoft.Practices.ObjectBuilder. I deployed my solution, tried my test page, only to find an error message saying partially trusted callers were not allowed. After examining the source code, I noticed that the AssemblyInfo file did not have the required AlllowPartiallyTrustedCallers attribute. So I thought fine, I'll just throw it in the GAC (against my own standards) and see if that works. Of course, it didn't work. It turns out ObjectBuilder also does not have AllowPartiallyTrustedCallers either.

The odd thing is that Microsoft released a patch for the 2.0 verison of Enterprise Library to allow partially trusted calers and supposedly it worked great. They claimed that it had that support also in the 3.1 release notes but in fact it is not there and it does not work. The reason being, that the assemblies are strongly named and none of the AssemblyInfos have the necesary attribute.

So how do we fix it? Well there are two options, both of which suck. For both options, you have to start by downloading the source code to ObjectBuilder (its on CodePlex). Open the solution, add the AllowPartiallyTrustedCallers attribute and compile it. Copy the dll it produces to the lib folder of your enterprise library. After you have done that, time to pick an option.

Probably the more correct way is to edit every AssemblyInfo file in Enterprise Library (including the unit tests) and add the AllowPartiallyTrustedCallers attribute. At the same time, you also have to add your own strong name key to every project as well. There are 38 projects in Enterprise Library so this definitely could be time consuming. You could shorten this list some by just doing the blocks you are interested in (i.e. just Logging), but it still quite a bit of effort. This also requires that your calling assemblies be strong names as well of course.

Option 2. Add the AllowPartiallyTrustedCallers attribute to the assemblies you need and recompile Enterprise Library without a strong name key. If you're only dealing with one application block, this is certainly faster. However, you have to modify every reference to the Enterprise Library dlls and remove the public key token (since its no longer signed). This is kind of a pain too, but its not too bad.

Either way you go, either everything has to be signed or nothing is signed. After you get Enterprise Library recompiled, you need to change the referenes in your existing projects, to use the new version of the dlls. Then of course you are still not done. Enterprise Library requires even more permissions than normal. Edit your manifest file, and add the following.

<IPermission class="AspNetHostingPermission" version="1" Level="Medium" />
<IPermission class="DnsPermission" version="1" Unrestricted="true" />
<IPermission class="EventLogPermission" version="1" Unrestricted="true">
  <Machine name="localhost" access="Administer" />
</IPermission>
<IPermission class="EnvironmentPermission" version="1" Unrestricted="true" />
<IPermission class="FileIOPermission" version="1" 
Read="$AppDir$;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config;"			   Write="$AppDir$"			   Append="$AppDir$"   
PathDiscovery="$AppDir$;C:\WINDOWS\Microsoft.NET\Framework\v
2.0.50727\CONFIG\machine.config"	/>
<IPermission class="IsolatedStorageFilePermission" version="1" Allowed="AssemblyIsolationByUser" 
UserQuota="9223372036854775807" />
<IPermission class="PrintingPermission" version="1" Level="DefaultPrinting" />
<IPermission class="PerformanceCounterPermission" version="1">
  <Machine name="localhost">
    <Category name="Enterprise Library Caching Counters" access="Write"/>
    <Category name="Enterprise Library Cryptography Counters" access="Write"/>
    <Category name="Enterprise Library Data Counters" access="Write"/>
    <Category name="Enterprise Library Exception Handling Counters" access="Write"/>
    <Category name="Enterprise Library Logging Counters" access="Write"/>
    <Category name="Enterprise Library Security Counters" access="Write"/>
  </Machine>
</IPermission>
<IPermission class="ReflectionPermission" version="1" Unrestricted="true"/>
<IPermission class="SecurityPermission" version="1"			   
Flags="SerializationFormatter, UnmanagedCode, Infrastructure, Assertion, Execution, ControlThread, ControlPrincipal, 
RemotingConfiguration, ControlAppDomain,ControlDomainPolicy"  />
<IPermission class="SharePointPermission" version="1" ObjectModel="True" />
<IPermission class="SmtpPermission" version="1" Access="Connect" />
<IPermission class="SqlClientPermission" version="1" Unrestricted="true"/>
<IPermission class="WebPartPermission" version="1" Connections="True" />
<IPermission class="WebPermission" version="1">
  <ConnectAccess>
    <URI uri="$OriginHost$"/>
  </ConnectAccess>
</IPermission>

Unfortunately, I do not have a version of the above that specified the full assembly path to each permission on the IPermission element, so that makes it necessary to make sure you have the following lines in the SecurityClasses element.

<SecurityClass Name="AllMembershipCondition" 
Description="System.Security.Policy.AllMembershipCondition, 
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="AspNetHostingPermission" Description="System.Web.AspNetHostingPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="DnsPermission" Description="System.Net.DnsPermission, System, Version=2.0.0.0, Culture=neutral, 
PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="EnvironmentPermission" 
Description="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="EventLogPermission" 
Description="System.Diagnostics.EventLogPermission, System, 
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="FileIOPermission" 
Description="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="FirstMatchCodeGroup" 
Description="System.Security.Policy.FirstMatchCodeGroup, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="IsolatedStorageFilePermission" 
Description="System.Security.Permissions.IsolatedStorageFilePermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="NamedPermissionSet" 
Description="System.Security.NamedPermissionSet"/>
<SecurityClass Name="PrintingPermission" 
Description="System.Drawing.Printing.PrintingPermission, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<SecurityClass Name="SecurityPermission" 
Description="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="SharePointPermission" 
Description="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"/>
<SecurityClass Name="SmtpPermission" 
Description="System.Net.Mail.SmtpPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="SqlClientPermission" 
Description="System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="StrongNameMembershipCondition" 
Description="System.Security.Policy.StrongNameMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="UIPermission" 
Description="System.Security.Permissions.UIPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="UnionCodeGroup" 
Description="System.Security.Policy.UnionCodeGroup, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="UrlMembershipCondition" 
Description="System.Security.Policy.UrlMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="WebPermission" 
Description="System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<SecurityClass Name="WebPartPermission" 
Description="Microsoft.SharePoint.Security.WebPartPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"/>
<SecurityClass Name="ZoneMembershipCondition" 
Description="System.Security.Policy.ZoneMembershipCondition, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

I spent a lot of time trying to figure this out today. Hopefully, this will help one of you if you need to use the Enterprise Library in SharePoint.