Test entry to put myself back on the blog map.
It's been a long time since my last log. Well I have been busy learning SPS search Filters, protocol handlers and was reading other's blogs rather than writing. Also one thing before I start of with SPS stuff. The timeout attribute I mentioned in my last blog works only with sync calls and would not work with async call/callbacks, I stand corrected on that thanks to Roy Chastain.
As soon as I got my feet wet(which basically meant I installed SPS server). Rahul, I am not really sure what I did that irked him off so much that he pushed me into the dark alleys of search, custom Filter and protocol handlers. Comming from the COM world where everything that can be thought of was already documented, the muddy waters of IFilters and protocol handlers were as clear to me as the swamps of florida which I had visited last weekend. So I decided to write my own implementation of IFilter and Protocol Handler. I am done with the Filter part now and would be working on the Protocol Handler comming weeks.I guess the real problem with someone like me who has not dealt much with searching and crawling components is that it's difficult to imagine where and how our component would be fit and who and when would our methods be called. Where here is my take on what I understood of it: Filters based on IFilter for MS Indexing server is what SPS uses to Fitler out contents, this was simple enough.
The whole design of SPS search is divided into two individual parts:
1. CRAWLING: In this phase the server will crawl any content source, i.e. a file share, a .html page etc. By crawling it means that it would try to extract text and properties of that document and index those in a flat file index. So a crawler would call a protocol handler based on what type of content source it is, the protocol handler would know how to open that content source and then call the IFilter implementation for the respective File type to get its properties and text.
2. SEARCHING: Once a content source has been indexed any search can be performed on this index. Isn't this cool.
Jumping straight to Filters. Filters are basically written to customize the content of a particular file type so it can be indexed efficiently. So for eg. if my app's document has a .ant extension and it stores the name of users in a struct. I would need a Filter to open the file, read the structures, get out the name inside the struct and save it in the indexer. That is the real power of IFilters.
Now how do we write one, heh heh, allright for all those code junkies(me included). Here is a good MSDN link for more technical details:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odc_SP2003_ta/html/ODC_HowToWriteaFilter.asp?frame=true
But basically to summarize Protocol handler would open a content source, get to a file, and based on its extension it would call the Filter that has been registered for that extension to index it. So basically we are interested in these 4 methods in a Filter:
1. Init: This is where you would do initialization for your filter.
2. GetChunk: This method gets called to read the file and get a chunk of text or properties.
3. GetText:
4. GetValue: Once a chunk has been read, GetValue or GetText would be called based on the chunk type that we set in GetChunk till it returns FILTER_E_NO_MORE_TEXT or FILTER_E_NO_VALUES.
That is it. That is all it requires to write a filter(well not really you would need to have a good understanding of COM, pointers, variant data types and C++ programming). The simplest thing to get started is the simpFilt sample that comes with SDK. To install the filter:
1. Compile it and regsvr32 the dll.
2. In Regedit goto HKLM\software\Microsoft\SPSSearch\ContentIndexCommon\Filters and add the name of the extension your filter will be crawling and in the default value put the CLSID of your dll.
3. From SPS portal site go to Site Settings->Configure Search and Indexing->Include File type and add the extension for your filter.
4. Now add a content source where the file with the registered extension is stored and do a full crawl and voila your filter is up and running.
Probably the best way to get a deeper look is to Open the filter project in VS.net and attach to the msadmn.exe process and put breakpoints on those 4 methods.
Currently I am writing a IFilter for Windows Media files(wmv and wma). It's gonna be pretty cool once its ready. I had some trouble with the Media Format SDK but couple of links from Santosh and I was reading those properties like Arial Font 16. My Filter can crawl the document and get the properties out but the indexer somehow is not indexing them properly. But i hope to sort that out this week.
Wow this log turned out to be pretty long but would post the Media filter as soon as its done.
This week while working on a case, I discovered how to set timeout values for Remoting calls which I though is pretty cool. We have missed this attribute a lot in DCOM.
We can specify the timeout attribute on the HttpChannel and that sets the time an Http request will wait in GetResponse() method of HttpWebRequest, before it throws an exception. That in remoting translates to when you make a remoting call(sync or async) the underlying channel will wait in GetResponse() for the remote method to return data for that time, if it does not return any response within the 'timeout' period, it would timeout and throw an exception in your remoting call. Cool isn't it.
This value is set to -1 or infinite lifetime by default, that basically means that remoting calls will block forever(yuckkk.) hence leading to client hanging if the server fails to respond. Now when we talk about async calls, then as soon as you shoot an async request it(underlying remoting) starts a HttpWebRequest and waits in GetResponse() for the async method to complete. Even though your class is not waiting on async call to finish and might be doing some other work in the meanwhile. But when your object tries to see if the async method actually returned an result or not at that point of time it would let you know whether the async method returned within the specified 'timeout' from the time you send the original async request if not then it will throw an exception.
How to set:
==========
Unfortunately I found some bugs related to this property having problem being read from config file. But it works great if you specify it programmatically:
IDictionary props= new Hashtable();
props[”timeout”] = 10000 ;//Wait for 10s in remote call.
//other properties like port etc.
HttpChannel chnl = new HttpChannel(props, .... ,....);
My name is Anant Vijay Dimri and till last fortnight I was working as DSE in OLE/COM team. I worked on OLE, COM, COM Interop, Remoting technologies for couple of years now. I found remoting to be of my interest though Interop also attracted my attention from time to time. Most of my posts would be in Remoting and Interop.
Currently I am moving to Sharepoint technologies within Microsoft and would continue to share my experiences in sharepoint as well.
Originally from busy city of New Delhi, India, I did my M.S. in Comp. Sc. from Univ of North Carolina. After a brief stint with XP team at Redmond, I joined Microsoft Charlotte.
Now and forever married to my wife Khushbu, we both live in sunny southern Queen city Charlotte.
This is my first blog, so jumping straight to the point. One intresting thing that I wanted to share for which I have not seen much documentation but people spending long hours figuring this out is how to pass credentials in .net Remoting.
Basically there would be two kinds of scenarios:
1. Passing default credentials:
i.e if a user wants to pass the windows credentials of the process along with the remoting request.In this scenario all you want to do is set the useDefaultCredentials property on the HttpChannel to true either programmatically:
props[“useDefaultCredentials“]=“true“
channel = new HttpClientChannel(ChannelProps, ClientBinFormatter);
or through configuration file:
<channel ref="http" useDefaultCredentials="true" />
2. Passing custom Credentials:
If you want to specify the username, password at runtime and want to pass it with the remoting request. This has been different with .net 1.0 and .net 1.1.
.net 1.0 : All you want to do is set the credentials property on your HttpChannel and all remoting requests through this channel sink will use the specified credentials.
nICredential credObj = new NetworkCredential(userName,password,domain);
Properties["credentials"] = credObj;
HttpChannel hc = new HttpChannel(channelProperties,…, .... );
n.net 1.1
nThis behavior is changed in .net 1.1 and now the credentials are needed to be set on each proxy, after you create it. This is easy when doing Server Activated object(SingleCall, Singleton). So for that you can easily do:
ICredential nc= new NetworkCredential(userName,password,domain);
nobject obj = Activator.GetObject (type, url);
nIDictionary dict = ChannelServices.GetChannelSinkProperties(obj);
n//set credentials on the proxy object
ndict["credentials"] = nc;
Setting credentials for CAO in .net 1.1
The catch with setting credentials on each proxy is that since Client activated objects sends a network request during 'new' or GetObject call, the credentials are already passed before you have your proxy. So to get around this problem if you want to pass custom credentials for CAO objects then we get the proxy to internal remoting object that is responsible for creating object on the server and set the credentials on that first.
1. CAO's are managed by internal Server objects so for CAOs we need to create a proxy to
<http://<localhost>/<vroot>/RemoteActivationService.rem>Set credentials on ChannelSink of this internal proxy
2. Now when we register and create the CAO on the client, the 'new' call will use the credentials set on RemoteActivationService.rem proxy.
3. Get the Channelsink of the CAO proxy
4. Set Credentials on the CAO proxy
This is how the sample code will look like:
ChannelServices.RegisterChannel(channel);
//Get a proxy for RemoteActivationService.rem this is an //internal object for CAO's
object obj = Activator.GetObject(typeof(RemObjects.MathObject), "http://localhost:80/RemObjects/RemoteActivationService.rem");
IDictionary dict = ChannelServices.GetChannelSinkProperties(obj);
//set credentials on the proxy object
dict["credentials"] = nc;
RemotingConfiguration.RegisterActivatedClientType(typeof(RemObjects.MathObject),"http://localhost:80/Rembjects/");
//get instance of your object
objMath = new RemObjects.MathObject(128);
//get channel sink object for your object and set credentials on that
dict = ChannelServices.GetChannelSinkProperties(objMath);
dict["credentials"] = nc;
Feel free to give me a feedback on this.