Office Communications Server 2007 is Microsoft's IP communication solution and it allows companies to leverage their network infrastructure for voice, video communication, instant messaging, audio/video calls and for much more. You may ask what's the benefit of using the computer network as opposed to the internal telephony network - you don't pay after the minute at neither of them. However, if it's the computer network, it's only the matter of software to integrate the telephony, video and IM with desktop applications. By routing the IP packages through a server in the DMZ, users can call each other at not cost wherever they are. The presence is also very important to mention - users can see each other's status (whether they are online, busy, away, on a meeting with their laptop, out of the office, etc). The presence icon is integrated into every Office applications and it tells the caller in advance whether the other party will be answering the call or not, or if it's not the right time for the call. This is integrated to every piece of the Office System (SharePoint and the Office client products). Online users will stop using mobiles, there's a whole change in the communication culture. This article outlines OCS 2007 Speech Server, which is an additional server role for Office Communications Server.
OCS 2007 Speech Server
Every software client/device is a UC endpoint in OCS - whether it's an IP phone, Office Communicator (the client of OCS, like Messenger), a video camera in an A/V meeting room, etc. Imagine that you have not only these endpoints, but that you also have non-human endpoints connected to your OCS/telephony infrastructure. These endpoints are software-driven and can communicate with callers on the phone. An example of such an endpoint is Exchange Server Voice Access, where you can get Exchange to read up your emails and you can do other clever things (say "Clear my calendar for today" - which sends a cancellation to every attendees of your meetings for today). You can write these applications using managed code and these application can be deployed and enabled in your OCS infrastructure. These numbers can be even enabled for callers outside of your organization (this is how Exchange Server Voice Access works at Microsoft).
How to write programs for Speech Server?
There are 3 important areas in a voice enabled system:
- Speech: the quality of the speech engine
- Voice recognition: the quality of the voice recognition engine and
- Programmability - how easy to develop voice-enabled applications on this platform.
I'll start with the programmability one and I let you to judge on the other two. There are two programming models that you can use: the web-programming model where the voice application is hosted in IIS as a web page and the dialog is represented by a set of post backs. The other programming model is using Windows Workflow Foundation to design the conversation's flow. I'll focus on the latter today and will skip the web-based one. For the workflow programming model, you need Visual Studio 2005 SP1, IIS, MSMQ and Speech Server installed on your PC (see the pre-requisites section).
Fire up your Visual Studio, there's a project template called "Voice Response Workflow Application" after you have install the development components. You can already start dragging and dropping workflow activities into your workflow designer to describe the conversation's flow. There are many workflow activities that you can use: Statement activity, QuestionAnswer activity, GetAndConfirm activity - this one won't step to the next activity unless the caller is confirmed his/her answer, Menu, etc. When your workflow asks something, you define the question for the activity, like "Can I have your employee ID please?", then you need to define what format you expect the answer in - this definition is called "Grammar". The grammar is a pre-defined pattern that defines the different ways the answer can be said. For example, "yes, it's 1234", or "my employee id is 1234", or "1234", or "it is 1234" and so on. We define a placeholder in this pattern for the number because that's the only thing that we are interested in, and we define the different options how the answer can be said. There's a designer that helps you creating the grammar.
The grammar will have an output variable which you can get when the caller is answered your question. Here, you need to write code - when the caller answered the question, you will get the employee ID into a variable that you can convert to a numeric value and you can do your actions based on this number - for example, you can look up this employee ID in Active Directory, etc.
I've prepared with a small application just to show how this thing works. What it does, it calls you up and it asks you about the number of computers and persons in your household and it submits the answers to a database. I could have written a more intelligent application as well, but this will be enough to understand how it works.
Prerequisites
To be able to play with the product, you need to install all components of it on your development environment.
In order to install the Speech Recognition Server component, you need to enable a few features if you don't have them already enabled. You need to re-start the installer every time you have enabled a feature - it won't refresh automatically. To save some time, copy my features list (Vista):
You also need Visual Studio 2005 with SP1 (VS 2005 RTM is no go), and the Visual Studio 2005 extensions for .NET Framework 3.0 (Windows Workflow Foundation) package in order to be able to install the Development Tools component of the product. Installing Visual Studio 2005 Service Pack 1 Update for Windows Vista is also recommended if you run Visual Studio 2005 on Vista.
After the product is set up, at least one language pack needs to be installed (you can find them on the installation DVD or your can download them from the Internet) for the Windows services to start. I've installed the English/UK pack. There's also a US and Australian English available on the DVD and 11 additional languages. The full list is:
- Chinese (People's Republic of China)
- Chinese (Taiwan)
- English (Australia)
- English (United Kingdom)
- English (United States)
- French (Canada)
- French (France)
- German (Germany)
- Italian (Italy)
- Japanese (Japan)
- Korean (Korea)
- Portuguese (Brazil)
- Spanish (Spain)
- Spanish (United States)
What is a Grammar? What is a Rule?
The "grammar" is a collection of "rules". A rule is a mini workflow where you can describe the expected sentence's structure. In my case, I expect the answer "I have X computer at home" or something similar from the end user. I designed my rule to accept a more sophisticated answer as well, like "I have only 2 computers at my household" or "I have got no computers". It's up to you how you make your rules finer and more resilient. The result of the rule is a value which is the number of computers in my case. The following is a screen shot of my rule from the Visual Studio Rule Editor:
The green shapes are called Lists, the white ones are Phrases. Only one of the Phrases apply inside a List shape. The pink shapes are Rule references (RuleRefs), they are used to reference to other rules. The two RuleRefs in my case are references to numeric rules, they are used to recognize the number 0 and the numbers 1 to 999 and convert the recognized words to a numeric value. Looking into those rules, they have several lines where they combine the recognized words and calculate the numeric result. The result is written to the $$._value member variable which is then copied to the $._value member variable by a Script Tag (blue). The value in $._value then can be referenced in the Voice workflow and can be used for further tasks (in my case, confirming the number of computers to the end user). After compiling the grammar, the outcome is an XML file, with a .grxml extension.
What is the Voice Workflow?
After designed the rule, let's work on the workflow part, which is the one that controls the main flow. The Rule that I've described above is evaluated in the HowManyComputers QuestionAnswer activity.
How can I start?
I recommend to install the developer samples. After installed, I suggest opening the HelloWorld project from the C:\Program Files\Microsoft Office Communications Server 2007 Speech Server\Samples\Workflow\HelloWorld folder and playing with it.
You can test your application by pressing F5 key - you'll get the Voice Response Debugging window where you need to click on the Call button:
When the workflow starts and the server asks you a question, you are redirected to the second tab and need to click on the Start Recording button. Say your answer and Speech Server will recognize it.
When your answer is recognized, click on the Submit button to post back your input to your workflow.
Questions?
Don't hesitate to ask!
I did a search on the Internet about the problem and couldn't really find anything useful.
Symptoms
You navigate to the Team Sites page and click on the "Site Map" link, you get the following message:
Unable to display this Web Part. The Table of Contents start location, /default.aspx, is unavailable. Check to see if this resource was moved or deleted.
Resolution
The TOC web part has a default.aspx at the end of the “Start From” location by default and it cannot handle this Url (it needs to be a site Url without a page name). This is how you can fix it (put the page into Edit mode first):
“Open the web part properties and see that the root ("start from") is
indeed set to /default.aspx. Simply change this to / and then the ToC works as
expected.”
Happy New Year! I hope that you had fun during the holidays and you didn't eat too much - or at least you can balance it with some gym exercise in the upcoming days. :)
A few weeks ago, I installed MOSS at a Customer here in Ireland and I had more difficulties than I ever expected. Part of the problems were due to product problems (hopefully, they will be solved by SP1), the other part was caused by a very strict Group Policy configuration. I chose the best ones and blogged here to help you guys out from the trouble:
SharePoint Timer Service Fails to Start
After the first restart on my fresh MOSS box, I got the famous error message on the logon screen: "At least one service failed to start". It turns out that it's the SharePoint Timer Service that failed to start. I get the following error message in the application log:
Source: Office SharePoint Server.Category: Office Server Shared Services.Event ID: 6482.Application Server Administration job failed for service instance Microsoft.Office.Server.Search.Administration.SearchServiceInstance (894b2244-ea64-4466-8aa3-99db5c7f6706). Reason: Logon failure: the user has not been granted the requested logon type at this computer Techinal Support Details: System.ComponentModel.Win32Exception: Logon failure: the user has not been granted the requested logon type at this computer at Microsoft.Office.Server.Search.Administration.SearchServiceInstance.SynchronizeDefaultContentSource(IDictionary applications) at Microsoft.Office.Server.Search.Administration.SearchServiceInstance.Synchronize() at Microsoft.Office.Server.Administration.ApplicationServerJob.ProvisionLocalSharedServiceInstances(Boolean isAdministrationServiceJob) If I fix it by re-typing the username and password, I get a popup saying the the account is granted a "Log on as a Service" right. Then after another restart, the problem starts again.
Resolution: for the first look, it seems the Windows forgets the password that I typed, but after some research, it turns out that the reason is that the account used to run the SharePoint Timer Service lost the "Log on as a Service" privilege due to Group Policy restrictions. Make sure that your service account has this right granted in the Local Security Policy snap-in.
SharePoint Doesn't Crawl People
The symptoms are that even if people objects were successfully imported, they are not crawled by MOSS search. The following error entry can be found in the crawl log and event log:
sps3://mysite/site$$$people
Error in PortalCrawl Web Service
Event ID: 2436
Category: Gatherer
Source: Office Server Search
The start address <sps3://did-spt-01:6376> cannot be crawled.
Context: Application 'Default SSP', Catalog 'Portal_Content'
Error in PortalCrawl Web Service. (0x80042617)
The content source Uri starting with sps3:// is the people database's content source. For some reason, by default, it's pointing to the SSP's Uri (address and port).
Resolution: changed the default sps3://did-spt-01:6376 to sps3://did-spt-01:80
DCOM Activation Errorsin the System Log:
I got an error in the system log:
Type: Error
Source: DCOM
Category: None
Event ID: 10016
Description:
The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID {61738644-F196-11D0-9953-00C04FD919C1} to the user XXX SID {XXX}. ...
Resolution: found that the GUID points to the IIS WAMREG admin Service DCOM app (dcomcnfg), however this user already had all activation permissions on it. Now, I granted all access permissions as well which solved the problem.
Access is Denied to the User Profile DB:
Event Type: Error
Event Source: Office SharePoint Server
Event Category: Office Server General
Event ID: 7888
Date: 9/01/2007
Time: 2:12:07 PM
User: N/A
Computer: xxxxxx
Description:
A runtime exception was detected. Details follow.
Message: Access Denied! Only site admin can access Data Source object from user profile DB.
Techinal Details:
System.UnauthorizedAccessException: Access Denied! Only site admin can access Data Source object from user profile DB.
at Microsoft.Office.Server.UserProfiles.SRPSite.AdminCheck(String message)
at Microsoft.Office.Server.UserProfiles.DataSource._LoadDataSourceDef(IDataRecord rec)
at Microsoft.Office.Server.UserProfiles.DataSource._LoadDataSourceDef(String strDSName)
at Microsoft.Office.Server.UserProfiles.DataSource..ctor(SRPSite site, Boolean fAllowEveryoneRead)
at Microsoft.Office.Server.UserProfiles.DataSource..ctor(SRPSite site)
at Microsoft.Office.Server.UserProfiles.UserProfileConfigManager.GetDataSource()
at Microsoft.Office.Server.UserProfiles.BDCConnector.RefreshConfiguration(String sspName)
Resolution: added the user profile import account to the local admins group on the MOSS box
By working together with one of our favorite Customers, we realized that the Microsoft NX-6000 webcam doesn't work with Office Communicator 2007. I'll address this to the product groups and ask them to publish it officially if they haven't yet.
By the way, it's a really nice piece of hardware and I love to use it with Messenger, but it seems that it's not Communicator's cup of tea. Hopefully you found this post early enough. My Customer went back to the hardware shop straight away and bought 3 pieces of VX-1000. We also tested and found that VX-6000 works fine with Communicator 2007.
Dear Colleagues at Intel Corporation!
Would it be so hard to release a video driver for my Toshiba Portege M400 that doesn't flicker and restores back to 800x600 almost every time I unlock my laptop? :) It ruins my productivity and lifts my blood pressure every time I start something.
I'll pay a couple of pints of original Irish GUINNESS to the person who fixes it. Thanks!
2nd Part:
My colleague, Levente Nagy came to me and advised to install the internal Toshiba driver pack that Toshiba and Microsoft built together for the internal Microsoft audience. It downgraded my driver from the version of 7.14.10.1322 to 7.14.10.1217 and it solved the problem. The device's name is Mobile Intel(R) 945GM Express Chipset Family. Thanks Levi!
My wife is seeking a job (by the way, aren't you looking for an experienced psychologist in Dublin, specialized for children? :) ) and we were going thru all these crazy expressions - like good eye for details, etc. So, I started thinking if I have a good eye for details and came to the conclusion that yes, I have, but I usually miss them. :) Here's my story from this morning: my mother and brother were here for visiting us. Yesterday was their last day here, today they are flying back to Hungary. Obviously, this was the longest night of the week, I got to bed after a few whiskies and beers, a bit later than 1 o'clock. Kati, my wife was doing all kinds of miracles to me to avoid the headache in the mornings meeting at our Customers. Back in time, just a few hours, I was quite surprised that my boss sent me a meeting request yesterday afternoon about this meeting - what a short notice.
Woke up at 7:30 with no headache but with a bit of balance. Struggled for about 15 minutes, then finally got out from the bed and started washing my teeth. I was running late. I had to run to catch the tram. I just seen the tram arriving and the queue at the ticket machine. So, I ran across the rails to the other tram stop to buy the ticket there. It was 10 cents more that what I expected (and had the exact amount minus 10 cents in my pocket), so I tried my 5 EUR notes. It didn't accept that one. I pulled off a 20 EUR notes and smashed it to the machine. It accepted and I felt myself a winner again, when it gave me back 18 EUR coins. Of course, I missed the tram. No problem, the next one came in 3 minutes, with an awful lot of people. I really had to stick myself among the passengers where they were standing like sardines in the box.
The tram has arrived to the Stephen's Green stop, I was walking from there in 10 minutes, making an unbeatable record. Finally, I got to the Customer, at 9:02. Called my boss, who meant to be there too, asking where he is. He didn't answer the phone. Then, when I hang the call, I realized that the location for the meeting is "Confcall" - thanks to Windows mobile. I had THAT feeling for a second. At this stage, my boss called me and asked what's up. I didn't tell him what happened, just told him that I'm going to dial in in a second. Finally, I did the confcall from the street next to the Customer's office. Our Customer was also on the train - I heard from the background noises. Lesson learned: have a good eye for the details! On the way back, I was laughing for long minutes. I have seen people with that stressful face that I had a few minutes ago. So, this is my story for today. Have a nice day and don't overlook the details! :)
During my demo environment installation (OCS and Exchange 2007), I got a few blockers that I couldn't find documented on the Internet. Maybe, it could be of your help. Here they are:
OCS Deployment:
Failure [0xC3EC7924] Schema definition for the requested Active Directory attribute isn't available. Please ensure local ADSI schema cache is up-to-date.
This problem occurred during the Deployment step of the OCS installation. Every AD schema preparation step ran successfully prior to this one. Checking the logs, it turns out that the AD schema class "Phone Route Usages" doesn't exist or there's a problem reaching it. The solution was to delete the schema cache file on the local server. The schema cache file is stored under C:\Windows\SchCache and this is used by ADSI to avoid the roundtrips to download the schema for every AD request. Simply delete the files stored in this folder (every domain has its own schema cache file) and re-run the installer.
There was a problem verifying the certificate from the server. Please contact your system administrator.
This problem occurred during the first logon with Office Communicator 2007. The resolution was to go to the server, start mmc, open the Certificates snap-in (computer account and local computer), find the root certificate (the issuer of the certificate used by OCS - VeriSign or your organization's KDC), export it to a file, and import it on the workstation. Don't accept the automatically determined location when importing the certificate on the client. Choose the folder yourself, it has to be the "Trusted Root Certification Authorities".
Presence icons didn't appear on the SharePoint site:
Presence icons are the result of a client-site JavaScript and ActiveX core running in the browser. Of course, they needs to be trusted. So, if your MOSS site is not trusted or not in an intranet zone (which is also treated as a "trusted" zone), this code won't be allowed to run. I found this info on Andrew Woodward's blog, thanks Andrew! :)
Exchange 2007:
Error: Opening package 'Z:\Exchange 2007\Setup\ServerRoles\UnifiedMessaging\umlang-en-US.msi' failed. This installation is forbidden by system policy. Contact your system administrator. Error code is 1625.
I got this one when tried to install the Unified Messaging Role for Exchange 2007. I tried to run the installer package from the network (mapped drive) which was forbidden by System Policy. So, copied it to the local disk.
The Unified Messaging server has encountered an argument that is missing or not valid: "AttachmentName".
I got this error message to the event log. I tried to create a fake voicemail message for the Unified Messaging service on Exchange 2007 by copying a WAV and TXT file to the UnifiedMessaging\Voicemail folder on the server. The TXT file is a descriptor that contains a link to the WAV file (the actual voicemail message). I dropped these 2 files together to the same folder, but it seems that the TXT file got there first and when UM got notified about the new file, it tried to open the WAV file which was not yet there. The resolution was to copy the WAV file first, and *THEN* the TXT (has to be very fast).
Free/Busy lookup was not working from Outlook
When tried to look up other user's F/B information, Outlook showed me a grey line (no information) for them. Enabled Outlook logging and the following error message was logged to the log file:
2007/08/27 14:29:57.431: Getting ASURL
2007/08/27 14:30:10.589: Failed to get ASURL. Error 8004010F
Checked with MfcMapi that the SCHEDULE+ FREE BUSY folder was accessible and it was populated with every mailbox. Then, asked some more clever guys and they told me that in order for F/B to work, AutoDiscovery also has to work. I could check how AutoDiscovery works by holding the Ctrl key and right-clicking on the Outlook icon in the system tray area and selecting the "Test E-mail Autoconfiguration" menu. From the dialog, I cleared the Guessmart and Secure Guessmart checkboxes, typed the email address and password of the current user and ran the test. It turns out that I needed another DNS entry with a name of autodiscover.yourCompany.com. Outlook then calls this host on SSL and tries to retrieve a file called autodiscover.xml to retrieve AutoDiscovery information. You can check if this request works: https://autodiscover.yourCompany.com/autodiscovery.xml - if it does, then try again and OOF will work now.
Last week, I visited one of my favorite Customers in Belfast. They experienced performance issues in their Customer's MOSS 2007 production environment.
Symptoms
The symptoms were the followings: a list item takes 10-20 seconds to open, sometimes more. Looking closer, it turns out that those list items are slow to open that are in a list that has a workflow associated and the workflow already finished running for the list item. The more time the list item is modified, the more time it takes to open it. My Customer is really a cool troubleshooter and he already found out these things, together with a SQL trace where it turns out that when the item is opened, the stored prodecure proc_GetListItemWorkflows is called too many times. If there were 2 modifications on the list item (so, the workflow ran 2 times already), it is called about 46 times, if it's 3, it's almost 100 times and so on. The stored procedure itself is just a SELECT statement and it's pretty fast, but the overhead to call the SP takes some time - especially when you do it 46 times. :) If the store procedure's contents are deleted, the problem is solved, but your MOSS box enters into an UNSUPPORTED STATE in this case. We found that the problem occurs only with sites based on the Content Publishing site template - so this means that WSS 3 sites are not affected.
Resolution
The problem was quite hard to identify. The reason why it was hard, because there were 2 bugs with the very same symptoms and we didn't know whether we fixed one and the other one was still there. Let's call them bug #1 and bug #2.
- Bug #1 was resolved by installing the latest official *CUMULATIVE* hotfix (Q939599) for MOSS 2007. For getting the hotfix, check the details at the end of this article. MOSS 2007 SP1 will contain the fix - and that's the best way to have this bug fixed in your production environment.
- Bug #2 is still there but we found a way to eliminate it (turn off the Office SharePoint Server Publishing feature on the Site features).
Even if we installed the hotfix and disabled the feature, the problem didn't disappear. We had to create a brand new site on the patched server and disable the feature on that one - in this case, the problem got solved on this very site.
What happens with data already in the list?
Data that was entered on the "bad" site before the hotfix is installed is “corrupted”. We tried stsadm -o export and stsadm -o import to export-import it to a patched site but it didn't work either. So, it seems that the patch causes list items to be stored in a different way - but the list items already stored on the "bad" site are in the bad format. My guess is that using the Datagrid view in the list to copy and paste the items will work. I will come back later with an update whether this one helped or not.
Getting the hotfix
You can obtain the hotfix by opening a support incident at Microsoft Product Support Services (see http://support.microsoft.com/gp/services/?LN=id for more info), contact CSS on the numbers at http://www.microsoft.com/services/microsoftservices/srv_support.mspx or use the email hotfix service at https://support.microsoft.com/contactus2/emailcontact.aspx?scid=sw;en;1410&WS=hotfix. In neither case you will be charged for obtaining the hotfix.
In Dublin it's always raining, so there's always some time to post a new article. Two useful code snippets for WSS3 developers:
Smartly export a document from a WSS Document Library:
// Set up the webclient with the correct credentials
WebClient webClient = new System.Net.WebClient();
webClient.Credentials = credential;
// Export the document to the given folder
webClient.DownloadFile(documentUrl, docFullPath);
Smartly import (upload) a document to a WSS Document Library:
// Set up the webclient with the correct credentials
WebClient webClient = new System.Net.WebClient();
webClient.Credentials = credential;
// Upload the file
webClient.UploadFile(destinationUrl, "PUT", sourceFilePath);
Today, I was playing with DLINQ and would like to share my findings with you. First of all, if you never heard of LINQ or want a basic intro, I suggest starting with the following 3 short videos (in order):
First of all, I generated a C# class file representing my SQL database tables by using a built-in SDK tool. The class is generated from my SQL database, called PfRep: I started an Orcas command prompt and stepped into the C:\Program Files\Microsoft Visual Studio 9.0\SDK\v3.5\Bin folder, then ran the following command:
sqlmetal /server:local host /database:PfRep /code /pluralize C:\blabla\PfRep.cs
This creates a .CS file with the class structure discovered from the database tables.
(by the way, the .CS file can be generated by a Visual Studio designer as well - by adding a "Linq to SQL File" file to the project - sqlmetal is good for re-generating the structure if it has changed.)
The first thing that's a bit weird is that the generated file contains modified table names. For example, I have the following tables in my PfRep database:
that (in PfRep.cs) were transformed to the following class names:
I guess, it doesn't want the programmer to mix up the classes (table definitions) with the property methods used to retrieve the records from the tables - or something like that. Let's write some easy code to run a query:
PfRep pfRep = new PfRep("database=PfRep;server=dszabo1");
var bigFolders =
from folder in pfRep.Folders
where folder.ItemCount > 1000
select folder;
foreach (Folder folder in bigFolders)
{
Console.WriteLine(folder.FolderKey + " " + folder.FolderTree.FolderTreeName);
Console.ReadLine();
}
What it does, it queries the Folder table for records with an item count larger than 1,000. Then it iterates through the results, looks up a referenced record (in the FolderTree table, which is referenced by Folder through the FolderTreeID property) and dumps out these data.
I was curious how does it spend the expensive transaction "fees" against SQL Server. :) It turns out that it's pretty clever. Here's what I captured with SQL Profiler. First, it queries for all the Folder records with an ItemCount larger than 1,000:
exec sp_executesql N'SELECT [t0].[FolderID], [t0].[FolderTreeID], [t0].[FolderName], [t0].[FolderKey], [t0].[Indexed], [t0].[ItemCount], [t0].[ParentFolderID], [t0].[ActionPlanID], [t0].[OwnerName], [t0].[OwnerEmail], [t0].[Note]
FROM [Folder] AS [t0]
WHERE [t0].[ItemCount] > @p0',N'@p0 int',@p0=1000
then when in the loop, it queries for the FolderTree record associated with the Folder record:
exec sp_executesql N'SELECT [t0].[FolderTreeID], [t0].[FolderTreeName], [t0].[DateCreated], [t0].[FolderTreeUrl]
FROM [FolderTree] AS [t0]
WHERE [t0].[FolderTreeID] = @p0',N'@p0 int',@p0=1
It checks whether the given FolderTree record was already retrieved and it doesn't run the query twice if already got the record - I'm wondering where does it store the results though ... and how.
sp_executesql is a good choice of running the queries, in my example, it's especially useful when running the FolderTree query (in the loop). Here's how it works:
"sp_executesql can be used instead of stored procedures to execute a Transact-SQL statement a number of times when the change in parameter values to the statement is the only variation. Because the Transact-SQL statement itself remains constant and only the parameter values change, the Microsoft® SQL Server™ query optimizer is likely to reuse the execution plan it generates for the first execution." http://msdn2.microsoft.com/en-us/library/aa933299(SQL.80).aspx
Sounds good, isn't it? I'm still very curious about how is the cached data stored, it could be an important question by Customers on large database projects. After some debugging and reverse-engineering, it turns out that the data is stored by using the type of the underlying entity (FolderTree in my case) and is indexed by a special generic collection.
Have fun with LINQ! :)
It happens all the time since every application uses MAPI to get some information from your MAPI profile. My advice is to close Microsoft Office Groove, Office Communicator, Messenger(s), the sidebar on Vista (I have 2 Outlook gadgets running there), every other application suspicous of using MAPI (getting any kinds of information from your inbox), every other Office applications, *THEN* close Outlook. It will exit smoothly. I guess, it's because the other applications are using a shared MAPI session that Outlook opened first and OUTLOOK.EXE holds that session.
This BDC-thing is awesome, but creating the XML file is like what Ford Fairlane said with the cheese grater. :) Tried with two 3rd party tools as well and they were not making it easier. Just one quick error message to share with the public, maybe it helps someone. later, I'll share the whole process, it's actually very nice.
ISSUE:
When configuring BDC to use a web service data source, you get an error message:
The LobSystem/LobSystemInstance Property 'WsdlFetchUrl' is missing
RESOLUTION:
The problem was that I was defining the WsdlFetchUrl property on the LobSystemInstance and not on the LobSystem level.
MORE INFORMATION:
This nice call stack maybe helps you find this article ;)
An exception was caught in BdcSearchPH interop while getting the Id stream:
Microsoft.Office.Server.ApplicationRegistry.MetadataModel.MissingMetadataPropertyException: The LobSystem/LobSystemInstance Property 'WsdlFetchUrl' is missing
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.WebServiceSystemPropertyParser.GetUri(NamedPropertyDictionary metadataObjectProperties, String uriPropertyName)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.ProxyAssemblyCache.GenerateProxyAssembly(String lobSystemName)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.ProxyAssemblyCache.MaterializeAssembly(String lobSystemName)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.ProxyAssemblyCache.GetProxyAssembly(String lobSystemName)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.WebServiceConnectionManager.GetDynamicProxyType(NamedPropertyDictionary lobSystemInstanceProperties)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.WebServiceConnectionManager.Initialize(NamedPropertyDictionary lobSystemInstanceProperties)
at Microsoft.Office.Server.ApplicationRegistry.Infrastructure.ConnectionManagerFactory.GetConnectionManager(LobSystemInstance systeminstance)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.WebServiceSystemUtility.Initialize(LobSystemInstance lobSystemInstance)
at Microsoft.Office.Server.ApplicationRegistry.SystemSpecific.WebService.WebServiceSystemUtility.ExecuteStatic(MethodInstance methodInstance, LobSystemInstance lobSystemInstance, Object[]& args)
at Microsoft.Office.Server.ApplicationRegistry.MetadataModel.DataClass.ExecuteInternal(LobSystemInstance lobSystemInstance, LobSystem lobSystem, MethodInstance methodInstanceToExecute, Method methodToExecute, ParameterCollection inputParameters, Object[]& overrideArgs)
at Microsoft.Office.Server.ApplicationRegistry.MetadataModel.Entity.ExecuteInternal(LobSystemInstance lobSystemInstance, LobSystem lobSystem, MethodInstance methodInstanceToExecute, Method methodToExecute, ParameterCollection inputParameters, Object[]& overrideArgs)
at Microsoft.Office.Server.ApplicationRegistry.MetadataModel.Entity.Execute(MethodInstance methodInstanceToExecute, LobSystemInstance lobSystemInstance, Object[]& overrideArgs)
at Microsoft.Office.Server.ApplicationRegistry.Search.IdEnumeratorChunker.FetchChunk(IEntityInstance preceedingEntityInstance)
at Microsoft.Office.Server.ApplicationRegistry.Search.IdEnumeratorChunker..ctor(MethodInstance idEnumerator, LobSystemInstance lobSystemInstance) at Microsoft.Office.Server.ApplicationRegistry.Search.ChunkingEntityInstanceEnumerator..ctor(MethodInstance idEnumerator, LobSystemInstance lobSystemInstance) at Microsoft.Office.Server.ApplicationRegistry.Search.SearchStaticHelper.GetEntityInstanceIdEnumerator(UInt32 entityId, UInt32 systemInstanceId)
at Microsoft.Office.Server.ApplicationRegistry.Search.SearchStaticHelper.GetEntityInstanceIds(UInt32 entityId, UInt32 systemInstanceId)
at Microsoft.Office.Server.ApplicationRegistry.Search.SearchStaticHelperWrapper.GetEntityInstanceIds(String sspAppId, UInt32 entityId, UInt32 systemInstanceId)
at GetEntityInstances(Char* pcwszAppName, gcroot<Microsoft::Office::Server::ApplicationRegistry::Search::EntityInstanceEnumeratorHandle ^>* gcEntityInstanceEnumeratorHandle, UInt32 uiEntityId, UInt32 uiSystemInstanceId, Void* hImpersonationToken)
Even if the question itself is very obvious, I got too many problems while implementing it. Here's the situation: I have a WinForms app (C#), I want to offer the user with creating a SQL database and a couple of database objects (SPs, tables) at the first time he/she runs the application.
The CREATE scripts are in a .sql file. It was generated with SQL Management Studio. If I read the file and pass it over to the SqlCommand object (as a string), it fails. If the file were just to contain CREATE TABLE statements, it would work, but ADO.NET doesn't like the CREATE PROC statements. If it's only CREATE PROC statements, it still fails. So, the principle is that every CREATE PROC has to run seperately. CREATE TABLEs can run together. So, what I did was, I was breaking the script to separate statements and ran them one by one by using the SqlCommand object. GO commands can be used to split up the file to multiple parts if there's no "GO" word in your script. Here it is:
// Break the SQL script to statements
// (delimited by the GO command).
// Without doing this, it doesn't work. NOTE: it's important that
// the SQL script shouldn't contain *ANY* GO word except the ones
// used to delimit, otherwise it won't work. We are using GO
// because OSQL also understands GO - so the script remains
// compatible. Another solution would be to use a
// commented delimiter.
string[] delimitedSqlCommand = databaseScript.Split(
new string[1] { "GO" }, StringSplitOptions.None);
// Creates the db objects
foreach (string sqlCommand in delimitedSqlCommand)
{
SqlCommand command = new SqlCommand(
sqlCommand, masterConnection);
command.CommandType = CommandType.Text;
command.ExecuteNonQuery();
}
I've been experiencing a strange problem today when I was using the MSADIPP.DLL (Microsoft Internet Publishing Provider) to query an Exchange public folder by using ADO. What I did was I was querying for the urn:schemas:httpmail:date field and ordering the results by this field. My query looks like this:
SELECT "urn:schemas:httpmail:date" FROM SCOPE('SHALLOW TRAVERSAL OF "http://blablabla"') WHERE "DAV:isfolder" = False and "DAV:ishidden" = False ORDER BY "urn:schemas:httpmail:date" DESC
... and I found that the first row returned (which should be the newest item in the folder) was a very old item and from a different folder (not even in the search scope below). So, I decided to update my DLL - regsrv32 /u then regsvr32 -ed a newer version and the problem gone away. Actually, I got a working version (11.0.5510.0) from a SharePoint 2003 installer CD, from the Support\ClientFlat\Files\PFiles\Common\System\OleDB folder, copied it over to C:\Program Files\Common Files\System\Ole DB and registered it. Happy days! :)
David
This is just a quick reference. A couple of blogs mentioning how to do that, but they forget to mention what to do if you have a Windows application (all examples are done with Console apps). So, here it is, briefly:
Let's say, I have 2 projects, one DLL and another one is an EXE Windows application project. I'm referencing the DLL project from the EXE project. Here's how to build and link them together:
1. Build all of you projects (including the EXE project) into netmodules:
cd DllProject
csc.exe /target:module *.cs
cd ../ExeProject
csc.exe /target:module *.cs /addmodule:../DllProject/Class1.netmodule
2. Link them together (and here's the trick that the Windows EXE project also has a Program.Main entry point but you don't see this one):
link /LTCG /verbose /entry:ExeProject.Program.Main /out:SingleFile.exe Form1.netmodule Class1.netmodule /subsystem:windows