Welcome to MSDN Blogs Sign in | Join | Help

Use a proxy page to realize OWA Single Sign-on

 

In a production environment, if customer sets Exchange OWA (Outlook Web Access) behind some external portal, after sign in the web portal, when access the OWA, most users don’t like re-type user name and password. We call this requirement as OWA SSO (Single Sign-on).

 

To achieve this goal, if the web portal is developed by SharePoint Server, we can leverage SharePoint SSO service. Many articles discussed this before:

 

http://technet.microsoft.com/en-us/library/cc262932.aspx 
http://deewaker-blogs.blogspot.com/2009/06/owa-sharepoint-integration-tricky.html
http://blogs.msdn.com/tconte/archive/2007/01/17/owa-web-part-with-single-sign-on.aspx

 

However, if the web portal was developed by different techniques, and we have no SharePoint SSO service, can we make this happen alternatively with reasonable efforts?

 

What I’m trying to do in this article is to use a proxy page, which will complete below tasks:

 

1. When a client request(1) comes to the proxy page

2. The proxy page uses HttpWebRequest to send POST request to the owaauth.dll, you can set your preferred account at this part. The function name is DoExchangeFBA, which is used
to simulate the From Based Authentication.
3. Get the secure cookies in Cookies container, which is responded from OWA.
4. In Page_Load function, convert the returned cookie as httpcookie, and store it to HttpResponse.
5. Redirect to OWA, now the request(2) has OWA required cookies. This step needs to put the proxy page in the same site as the OWA, otherwise cookie will be removed by IE when redirecting the request (1). And OWA must be Form Authentication Mode.

 

The request flow is:

 

a. Provide login Info                                             

b. Post to OWA                        

c. Get Authenticated Cookies  from OWA                    

d. Send requests with Authenticated Cookies

 

Client -----[a]-----àProxy Page-----[b]-----àOWA-----[c]-----àClient-----[d]-----àOWA

 

Below is sample code of the proxy page for your reference, the key is to use CookieContainer get the cookie from OWA and convert it to the HttpCookie,so that client can use the HttpCookie in next redirected request.

 

This method can be used to other SSO scenarios when the second site supports Form Based Authentication. When use the proxy page, please be careful on make the user login information secure.

 

 

 

public partial class _Default : System.Web.UI.Page

 

{

    CookieCollection DoExchangeFBA(string server, string  userName, string password)

 

{

 

    string uri = server + "/owa/auth/owaauth.dll";

 

    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);

 

    request.Method = "POST";

    request.CookieContainer = new CookieContainer();

    request.ContentType = "application/x-www-form-urlencoded";

    request.AllowAutoRedirect = false;

    request.ServicePoint.Expect100Continue = false;

   

    server = HttpUtility.UrlEncode(server);

 

    userName = HttpUtility.UrlEncode(userName);

    password = HttpUtility.UrlEncode(password);

 

    string  bodyString = "destination={0}&flags=0&username={1}";

    bodyString += "&password={2}&SubmitCreds=Log+On&";

    bodyString += "forcedownlevel=0&trusted=0&isUtf8=1";

 

    bodyString = string.Format(bodyString, server,

                                userName, password);

 

    byte[] body = Encoding.ASCII.GetBytes(bodyString);

 

    request.ContentLength = body.Length;

 

    ServicePointManager.Expect100Continue = false;

    Stream stream = request.GetRequestStream();

    stream.Write(body, 0, body.Length);

    stream.Close();

 

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();

 

    if (response.Cookies.Count < 2) throw

        new AuthenticationException("Failed to login to OWA!");

 

    return response.Cookies;

}

 

 public static bool AcceptAllCertificatePolicy(object sender,

                                               X509Certificate certificate,

                                               X509Chain chain,

                                               SslPolicyErrors sslPolicyErrors)

{       

       return true;

}

 

protected void Page_Load(object sender, EventArgs e)

 

{

        ServicePointManager.ServerCertificateValidationCallback +=

        AcceptAllCertificatePolicy;

 

        CookieCollection CookieCol = DoExchangeFBA("https://" + "mailserver",  

        "domain\\user", "p@ssw0rd");       

       

        int i = 0;

       

        foreach (Cookie cookie in CookieCol)

        {      // Access to each cookie here   

            System.Web.HttpCookie Hcookie = new           

            System.Web.HttpCookie(cookie.Name, cookie.Value);

            Hcookie.Expires = cookie.Expires;

            Response.Cookies.Add (Hcookie);

            i++;

        }

       

        Response.Redirect("https://mailserver/owa/");

 }

 

           

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Happy New Year!

 

Best Regards,

 

Freist Li

.NET application may crash when calling function from native C++ dll

 

Symptom

===========

Customer built an ASP.NET web application using Visual Studio 2008 on Windows 2008. In the source code, it called a function which was imported from native c++ dll:

 

[The source code looks like below]

 

public partial class _Default : System.Web.UI.Page

 {

        protected void Page_Load(object sender, EventArgs e)

        {

        }

        [System.Runtime.InteropServices.DllImport("PinvokeLib.dll", EntryPoint = " TestStringAsResult", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]

        public static extern string TestStringAsResult();

                ……

        protected void Button_Click(object sender, EventArgs e)

        {

            string str = TestStringAsResult();

        }

}

 

Above code seems working fine during debugging when "Use Visual Studio Development Server" in Web properties. However, when choose the web properties to “Use IIS Web Server”,  the web page seems hang and returns server internal error message. This issue will not occur on Windows 2003.

 

Troubleshoot

===========

We got the source code of native c++ dll and the related method was written like below:

 

extern "C" PINVOKELIB_API char * TestStringAsResult()

{

   return "Test String";

}

 

We rebuilt the native dll and web application with VS 2008 on a test Windows 2008 server. When we ran the web application, w3wp.exe crashed and WerFault.exe (Windows Error Reporting service) showed up trying to record logs. In the application event log, we found 0xc0000374 exception:

Log Name:      Application

Source:        Application Error

Date:          12/12/2009 3:37:00 AM

Event ID:      1000

Task Category: (100)

Level:         Error

Keywords:      Classic

User:          N/A

Computer:      182462M

Description:

Faulting application w3wp.exe, version 7.0.6001.18000, time stamp 0x47919413, faulting module ntdll.dll, version 6.0.6001.18000, time stamp 0x4791a7a6, exception code 0xc0000374, fault offset 0x000b015d, process id 0x10e0, application start time 0x01ca7b1f684ff683.

 

0xc0000374 indicates that there is heap corruption issue existed. We used DebugDiag to catch w3wp.exe crash dump file and found below call stack:

 

0:023> kL200

ChildEBP RetAddr 

052deaf4 77df0d68 ntdll!RtlReportCriticalFailure+0x5b

052deb04 77df0e56 ntdll!RtlpReportHeapFailure+0x21

052deb38 77db0531 ntdll!RtlpLogHeapFailure+0xa1

052deb64 7680c56f ntdll!RtlFreeHeap+0x60

052deb78 77c3dc2c kernel32!HeapFree+0x14

052deb8c 77c3dc53 ole32!CRetailMalloc_Free+0x1c

052deb9c 7a0dce06 ole32!CoTaskMemFree+0x13

052debac 7a0e06c2 mscorwks!DefaultMarshalOverrides<CSTRMarshalerBase>::ReturnCLRFromNative+0x35

052dede8 79e957c3 mscorwks!RunML+0x949

052dee68 79e956b7 mscorwks!NDirectGenericStubPostCall+0x194

052deef4 79e85686 mscorwks!NDirectGenericStubReturnFromCall+0x1f

052deefc 051f0678 mscorwks!NDirectSlimStubWorker2+0x13d

WARNING: Frame IP not in any known module. Following frames may be wrong.

052def38 04836dee 0x51f0678

052def50 04836fdc System_Web_ni+0x276dee

00000000 00000000 System_Web_ni+0x276fdc

 

0:023> !clrstack

OS Thread Id: 0xb4c (23)

ESP       EIP    

052def14 77df015d [NDirectMethodFrameGeneric: 052def14] WebApplication3._Default.__PBExternal_fnreturnenstra()

052def24 051f0678 WebApplication3._Default.Button1_Click(System.Object, System.EventArgs)

052def44 04836dee System.Web.UI.WebControls.Button.OnClick(System.EventArgs)

052def58 04836fdc System.Web.UI.WebControls.Button.RaisePostBackEvent(System.String)

……

052df2ec 04663072 System.Web.HttpRuntime.ProcessRequestNoDemand(System.Web.HttpWorkerRequest)

052df2f8 0466157b System.Web.Hosting.ISAPIRuntime.ProcessRequest(IntPtr, Int32)

 

We could see that CoTaskMemFree was called to free unmanaged memory in this situation. The problem is due to CLR use different protocol to allocate memory and free memory between managed code and unmanaged code. According to below MSDN article, when CLR marshals unmanaged memory to the string, it will always invoke CoTaskMemFree method to free the unmanaged memory:

“Memory Management with the Interop Marshaler”

<http://msdn.microsoft.com/en-us/library/f1cf4kkz(VS.80).aspx>

 

Since the unmanaged memory is not allocate by CoTaskMemAlloc, it will crashed by

ntdll!RtlpLowFragHeapFree checking. This issue will also happen if we use NEW or malloc function to allocate memory in C++ dll. Below code will fail as well:

 

TCHAR* WINAPI TestStringAsResult()

{

TCHAR *ret;

ret = new TCHAR[10];

wcscpy(ret, L"test");

return ret;

}

 

To fix this problem, we need to explicitly call CoTaskMemAlloc method to allocate memory in native dll:

 

#include <objbase.h>

……

extern "C" PINVOKELIB_API char * TestStringAsResult()

{

    STRSAFE_LPWSTR result = (STRSAFE_LPWSTR)CoTaskMemAlloc( 64 );

    StringCchCopy( result, sizeof(result) , (STRSAFE_LPWSTR)"This is return value" );

    return (char *) result;

}

 

If the unmanaged memory is not allocated with the CoTaskMemAlloc method and could not be changed, we must use an IntPtr and free the memory manually using the appropriate method. The declaration in c# should be changed from:

 

[System.Runtime.InteropServices.DllImport("PinvokeLib.dll", EntryPoint = " TestStringAsResult", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]

        public static extern string TestStringAsResult();

 

To:

 

[System.Runtime.InteropServices.DllImport("PinvokeLib.dll", EntryPoint = " TestStringAsResult", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]

        public static extern IntPtr TestStringAsResult();

 

Another Question

===========

Why this problem doesn’t happen under Win2003?

It is because that Windows Vista and Win2008 support new heap verification feature.

“HeapEnableTerminationOnCorruption”

<http://msdn.microsoft.com/en-us/library/aa366705.aspx>

 

It enables the terminate-on-corruption feature. If the heap manager detects an error in any heap used by the process, it calls the Windows Error Reporting service and terminates the process. So the heap corruption issue will be reported by Win2008 or Vista explicitly while Win2003 OS doesn’t report this though the heap corruption indeed exsits.

 

More Information

===========

Below two articles provides the sample code of calling native c++ dll function within c#:

 

“Strings Sample”

http://msdn.microsoft.com/en-us/library/e765dyyy(VS.80).aspx

 

“PinvokeLib.dll”

http://msdn.microsoft.com/en-us/library/as6wyhwt(VS.80).aspx

 

 

References

===========

Marshaling between Managed and Unmanaged Code

http://msdn.microsoft.com/en-us/magazine/cc164193.aspx

Default Marshaling for Strings

http://msdn.microsoft.com/en-us/library/s9ts558h(VS.80).aspx

Default Marshaling for Arrays

http://msdn.microsoft.com/en-us/library/z6cfh6e6(VS.80).aspx

Memory Management with the Interop Marshaler

http://msdn.microsoft.com/en-us/library/f1cf4kkz(VS.80).aspx

Regards,

Hanson Wang 

 

ASP cannot open encrypted Access 2007 database file via ODBC

 

Symptom:

To reproduce the issue:

1.        Install “2007 Office System Driver: Data Connectivity Components” in order to open the new Access 2007 .accdb database file.

http://www.microsoft.com/downloads/details.aspx?familyid=7554F536-8C28-4598-9B72-EF94E038C891&displaylang=en

 

2.        Place an .accdb Access 2007 database file on server.

The database is password encrypted.

 

3.        Setup an ODBC system DSN and point it to the .accdb database file.

Enter the database password in advanced options dialog box.

 

4.        Open the database in ASP page

<%

dim cn

set cn=server.createobject("adodb.connection")

cn.open "dsn=dsn1"

%>

This error message occurs:

Error 0x80004005 “Not a valid password”

 

Troubleshooting:

However similar .vbs code works.

dim cn

set cn=createobject("adodb.connection")

cn.open "dsn=dsn1"

And ASP works if the database is not encrypted.

Resolution:

In order to let it work, you must apply “Microsoft Office Access Runtime and Data Connectivity 2007 Service Pack 2 (SP2)” first.

http://www.microsoft.com/downloads/details.aspx?FamilyId=6F4EDEED-D83F-4C31-AE67-458AE365D420&displaylang=en

 

And then grant read/write permission to .accdb database file and .laccdb lock file to the IIS anonymous user account.

NOTE: Access is not recommended for server environment, for better performance and scalability, please using SQL server instead.

Best Regards,

Juntao Zhu

Posted by dsifof | 1 Comments

DllCanUnloadNow function isn't invoked after using classic COM components in .NET applications

 

COM Interop is a technic  for calling an unmanaged COM component from a .NET application, please refer to http://msdn.microsoft.com/en-us/magazine/dvdarchive/cc163494.aspx to learn how to implement it. DllCanUnloadNow is an important function which should be implemented and exported by the COM component.

However, you may be aware that the DllCanUnloadNow function isn't invoked with the managed client if we don't explicitly call CoUninitialize function. In this article, I'd like to explain why the DllCanUnloadNow function isn't invokved.

How DllCanUnloadNow is invoked in native client

At first, let's have a look at how the native client is implemented in C++ code.

void main(void)

{

     // Declare and HRESULT and a pointer to the Simple_ATL interface

     HRESULT              hr;

     IFirst_ATL      *IFirstATL = NULL;

 

     // Now we will intilize COM

     hr = CoInitialize(0);

 

     // Use the SUCCEDED macro and see if we can get a pointer to

     // the interface

     if(SUCCEEDED(hr))

     {

           hr = CoCreateInstance( CLSID_First_ATL, NULL, CLSCTX_INPROC_SERVER,

                IID_IFirst_ATL, (void**) &IFirstATL);

          

           // If we succeeded then call the AddNumbers method, if it failed

           // then display an appropriate message to the user.

           if(SUCCEEDED(hr))

           {

                long ReturnValue;

 

                hr = IFirstATL->AddNumbers(5, 7, &ReturnValue);

                cout << "The answer for 5 + 7 is: " << ReturnValue << endl;

                hr = IFirstATL->Release();

           }

           else

           {

                cout << "CoCreateInstance Failed." << endl;

           }

     }

     // Uninitialize COM

     CoUninitialize();

}

Please note, we never forget to invoke CoUninitialize function after we finish using the COM object.  The DllCanUnloadNow function will be triggered when calling CoUninitialize function, please refer to the following callstack.

0:000> k

ChildEBP RetAddr 

0012fe94 776bb927 simple_atl!DllCanUnloadNow [C:\comtest\COM_ATL_Object_Src\Simple_ATL.cpp @ 43]

0012fea8 77691b90 ole32!CClassCache::CDllPathEntry::CanUnload_rl+0x3b 

0012fef4 7769182a ole32!CClassCache::CleanUpDllsForApartment+0x12e

0012ff20 7769174c ole32!FinishShutdown+0xd7

0012ff40 776bce20 ole32!ApartmentUninitialize+0x94 

0012ff58 776bcdd2 ole32!wCoUninitialize+0x7d 

0012ff74 00401087 ole32!CoUninitialize+0x65 

 

How to make the DllCanUnloadNow be invoked in managed client

 

At first, let's have a look at the common managed client code.

class Test

{

    static void Main()

    {

        MyCOMServerClass comServer = new MyCOMServerClass();

        comServer.MyCOMServerMethod();

        System.Runtime.InteropServices.Marshal.ReleaseComObject(comServer);

    }

}

In COM Interop, we don't need to call CoInitialize function as the .NET framework will call it automatically. But .NET framework won't call CoUninitialize automatically; this is why the DllCanUnloadNow function will never be triggered.

So, we need to call CoUninitialize explicitly by using P/Invoke of ole32.dll. Please refer to the following codes.

class Test

{

    [DllImport("ole32.dll")]

    extern static void CoUninitialize();

    static void Main()

    {

        MyCOMServerClass comServer = new MyCOMServerClass();

        comServer.MyCOMServerMethod();

        System.Runtime.InteropServices.Marshal.ReleaseComObject(comServer);

        CoUninitialize();

    }

}

 

Note: In this scenario, we need to call the CoUninitialize function when the application is closed. Although .NET will delay COM dll unloading, with CoUninitialize we can ensure the DllCanUnloadNow will be hit before process exits. To unload COM dll without such delay, please consider using CoFreeUnusedLibrariesEx(0,0).

References

DllCanUnloadNow Function: http://msdn.microsoft.com/en-us/library/ms690368(VS.85).aspx

CoUninitialize Function: http://msdn.microsoft.com/en-us/library/ms688715(VS.85).aspx

How to use COM components in Visual Studio .NET: http://support.microsoft.com/kb/816152

Beginner's Tutorial: COM/ATL Simple Project: http://www.codeproject.com/KB/atl/com_atl.aspx

Improving Interop Performance: http://msdn.microsoft.com/en-us/library/ms998551.aspx

Regards,

Zhixing Lv

The “page cannot be displayed” error occurs due to incorrect IIS installation

 

Customer has an IIS 6.0 with SMS installed.

 

When access one of the SMS virtual directory, IE showed “page cannot be displayed” error with a button asking you to troubleshoot connection problem. There was no entries logged in IIS log, however we could found a “connection dropped” error for each request in http error log.

 

This sounds a SSL handshake issue as this site requires mutual SSL authentication. Requests will be disconnected by HTTP.SYS as long as SSL handshake failed, and never be passed to the work process. We did a quick test on plain html file, and it works. Then, this told us that SSL has no problem. Problem should be due to the SMS extension. Then, we reviewed the SMS logs and there was an error related to network like “network connection was closed”. This didn’t give us too much help. After enabled IIS debug trace, we found something really weird as we could see the request was passed and handled by the SMS extension.

 

1.     SSL handshake succeeded.

 

00000605          43.71051407      [472] 8072 strmfilt!SSL_STREAM_CONTEXT::DumpCertDebugInfo [\sslcontext.cxx @ 3202]:Client cert key length = 2048 bits  

00000606          43.71069336      [472] 8072 strmfilt!SSL_STREAM_CONTEXT::DumpCertDebugInfo [\sslcontext.cxx @ 3240]:Client cert issuer = DC=com, DC=XXX, DC=internal, DC=pc, CN=XXX Group Ltd Issuing       

00000607          43.71074677      [472] 8072 strmfilt!SSL_STREAM_CONTEXT::DumpCertDebugInfo [\sslcontext.cxx @ 3283]:Client cert subject = CN=XXX       

00000608          43.71078110      [472] 8072 strmfilt!SSL_STREAM_CONTEXT::DumpCertDebugInfo [\sslcontext.cxx @ 3344]:Client cert verification result = 0x0 (SUCCESS) 

 

2.     The request was passed to SMS extension.

 

00000657          43.82388306      [7588] 8184 w3isapi!ISAPI_DLL::Load [\dll_manager.cxx @ 389]:ISAPI_DLL::Load() Loaded extension c:\program files\sms_ccm\getauth.dll,  description "MP GetAuth ISAPI Extension"

00000658          43.82393265      [7588] 8184 w3isapi!ProcessIsapiRequest [\w3isapi.cxx @ 572]:   

00000659          43.82393265      [7588]   Calling into HttpExtensionProc    

00000660          43.82393265      [7588]     Extension: 'c:\program files\sms_ccm\getauth.dll'

00000661          43.82393265      [7588]     pECB: 010D59B8        

00000662          43.82393265      [7588]   <END>            

00000663          43.82393265      [7588] 

 

3.     Request was succeeded with 200:

 

00000678          44.69152832      [7588]   HSE_REQ_SEND_RESPONSE_HEADER_EX[010D59B8]: Function Entry       

00000679          44.69152832      [7588]     Status: '200 OK'         

00000680          44.69152832      [7588]     Headers: 'Content-Length: 1401           

00000681          44.69152832      [7588] Content-Type: text/xml   

00000682          44.69152832      [7588] Cache-Control: no-cache

00000683          44.69152832      [7588] Pragma: no-cache          

00000684          44.69152832      [7588] 

 

4.     SendResponse failed with a network error:

 

00000687          44.69168472      [7588] 4024 w3core!W3_CONTEXT::SendResponse [\w3context.cxx @ 2338]:SendResponse failed: handler ISAPIHandler, hr 80070057   

00000690          44.69181824      [7588] 4024 w3isapi!SSFSendResponseHeaderEx [\server_support.cxx @ 284]:

00000691          44.69181824      [7588]   HSE_REQ_SEND_RESPONSE_HEADER_EX[010D59B8]: Failed.      

00000692          44.69181824      [7588]     Error: 0x80072746  

00000693          44.69181824      [7588]   <END>            

 

The cause:

 

Customer’s server is Windows 2003 SP2, however the IIS binaries are RTM. This was an incorrect installation. This was fixed by:

-       Reinstall IIS, when installation prompts for Windows 2003 CD, provides a Windows 2003 CD with SP2.

-       Or re-apply SP2.

 

014> lmvm kernel32

start    end        module name

77e40000 77f42000   kernel32   (private pdb symbols)

    Image path: c:\winnt\system32\kernel32.dll

    Image name: kernel32.dll

Timestamp:        Sun Mar 22 01:08:26 2009 (49C51F0A)

FileVersion:      5.2.3790.4480 (srv03_sp2_gdr.090321-1244)

    FileDescription:  Windows NT BASE API Client DLL

    LegalCopyright:   © Microsoft Corporation. All rights reserved.

 

0:014> lmvm w3core

start    end        module name

5a390000 5a3e5000   w3core     (private pdb symbols)

    Image path: c:\winnt\system32\inetsrv\w3core.dll

    Image name: w3core.dll

    FileVersion:      6.0.3790.0 (srv03_rtm.030324-2048)

    FileDescription:  IIS Web Server Core

LegalCopyright:   © Microsoft Corporation. All rights reserved.

 

 

See you next time,

Zhao Wei

 

Posted by dsifof | 0 Comments

Why cannot this ASP.NET application domain be unloaded?

 

Symptom:

According to the dump file, there are dozens of application domains for one asp.net web application.

Troubleshooting:

Asp.net starts new appdomain and unloads old one in various scenarios, for example:

·         Machine.Config, Web.Config or Global.asax are modified

·         The bin directory or its contents is modified

·         The number of re-compilations (aspx, ascx or asax) exceeds the limit specified by the <compilation numRecompilesBeforeAppRestart=/> setting in machine.config or web.config  (by default this is set to 15)

·         The physical path of the virtual directory is modified

·         The CAS policy is modified

·         The web service is restarted

·         (2.0 only) Application Sub-Directories are deleted (see Todd’s blog http://blogs.msdn.com/toddca/archive/2006/07/17/668412.aspx  for more info)

This blog article describes the behavior for more details: http://blogs.msdn.com/tess/archive/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles.aspx

It will fail to unload the old AppDomain if you are stuck inside unmanaged code which performs an uninterruptable blocking operation.

A System.CannotUnloadAppDomainException will occur and can be found in the dump.

Below is a typical call stack when AppDomain will fail to be unloaded, System.Net.Sockets.Socket.Receive is doing uninterruptable blocking operation:

Child-SP         RetAddr          Call Site

000000000362d410 00000642749e90b0 DomainNeutralILStubClass.IL_STUB(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)

000000000362d4f0 00000642749e9174 System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)

…….

000000000362dd00 000006427f62ff5d System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)

 

Resolution:

To fix the issue you should prevent the code from calling inside unmanaged code which performs an uninterruptable blocking operation when AppDomain is unloading.

We did a test to use a background thread calling System.Net.Sockets.Socket.Receive always. When reload new AppDomain, the same System.CannotUnloadAppDomainException occurs.

A recycling of application pool process w3wp.exe will force IIS to unload all AppDomains. It can be considered as a workaround.

Regards,

Juntao Zhu

Error “setup was unable to load the master information file”

 

Symptom:

When clicking “Add/Remove Windows Components” in control panel, it shows error “setup was unable to load the master information file” and rejects further action.

Troubleshooting:

This error occurs when master information file %windir%\inf\sysoc.inf is missing. This can happen when system is restored from an invalid backup or malicious software has deleted important system files.

You can restore the INF file from another Windows 2003 server with the same service pack.

Some components like IIS may still be missing from the check list after restoring the INF file. You can try to restore %windir%\inf\iis.inf from a reference server to add IIS.

Resolution:

Restore the INF files mentioned above to fix the issue.

 

Regards,

Juntao Zhu 

 

Analyze .NET Fusion log with PowerShell in timely manner

 

In my previous post, I give one sample on how to use Powershell to filter and categorize information from thousands of IIS7 FREB log files.

 

Here is another sample to quickly find out useful information from .NET fusion log with PowerShell.  Here we go:

 

Problem Description

===============

Customer’s web application reported this “Exception has been thrown by the target of an invocation” error message when the application is loading at the first time:

ConfigurationErrorsException

Exception has been thrown by the target of an invocation. (C:\inetpub\wwwroot\wss\VirtualDirectories\somesitename\web.config line 100)

 

   

 

 

 

 

Analysis

========

Look at the web.config file, the line indicates it is an “Add Provider” child element under Sitemap section, such as:

<siteMap defaultProvider="CurrentNavSiteMapProvider" enabled="true">

      <providers>

          <add name="CustomizedProvider" type="My application.portal.namespace, Myapplication.Portal, Version=1.0.0.0, Culture=neutral, PublicKeyToken=71e9bc3234211e9429c" />

 

 

 

 

 

 

 

 

The issue doesn’t happen to other Dev machines. We double confirmed that the provider assembly has been registered in GAC correctly and the configuration is no problem.

 

This means the problem happened during .NET fusion (Fusion means .NET Framework sub-system is locating and loading assemblies). We enabled Fusion log to find out what happens when the .net 2.0 web application starts running:

 

Under HKLM\Software\Microsoft\Fusion

a. Create a DWORD value named ForceLog and set the value to 1.
b. Create a String value named LogPath, set the value as c:\temp

c.  Create the C:\temp folder.

Note: Ensure the c:\temp is empty.

After this, restart IIS to force all assemblies will be reloaded.

 

 

While reproducing the same error, there are many fusion logs generated in c:\temp.

 

In fusion log, it has one line in content to indicate error or not, for example:

 

Bind result: hr = 0x0. The operation completed successfully.

 

 

 

 

 

Or

 
Bind result: hr = 0x80070002. The system cannot find the file specified.

 

 

 

 

 

But we cannot see this information from file title directly:

 

ps1.jpg

 

In this situation, I run this command in PowerShell:

 

select-string "Bind result: hr = 0x8" *.HTM  |format-table filename -groupby line

 

The command can help us to filter out all failed Fusion log files grouping by different Bing error code.

 

ps2.JPG

By comparing the scenario on good machine, we quickly identified that missing System.XML.Linq is the root cause.

After applying .NET 3.5 SP1 (which contains System.XML.Linq), problem was resolved.

Best Regards,

Freist Li

 

Fail to start W3SVC: The parameter is incorrect

 

Symptom

 

When start World Wide Web Publishing Service service, the following Service error message popup

 

Could not start the World Wide Web Publishing Service service on Local Computer.

Error 87: The parameter is incorrect.

 

In the system log, Event 7000 was logged:

 

Event Type:   Error

Event Source: Service Control Manager

Event Category:       None

Event ID:       7000

Date:            11/26/2009

Time:            3:49:37 PM

User:            N/A

Computer:     XXXXX

Description:

The World Wide Web Publishing Service service failed to start due to the following error:

The parameter is incorrect.

 

Troubleshooting

 

Run net start command, still get the same issue:

 

net start w3svc

 

Run the Process Monitor log, we found there is no service command to start executing the World Wide Web Publishing Service (i.e. C:\WINDOWS\System32\svchost.exe -k iissvcs)

 

Events should be similar with below when starting W3SVC on good IIS box.

 

12:26:26.6020853 PM             1040        services.exe           400          Process Create                C:\WINDOWS\System32\svchost.exe   SUCCESS               PID: 10692, Command line: C:\WINDOWS\System32\svchost.exe -k iissvcs

12:26:26.6020970 PM             1041        svchost.exe            10692      Process Start                          SUCCESS                Parent PID: 400

12:26:26.6021233 PM             1042        svchost.exe            10692      Thread Create                        SUCCESS                Thread ID: 11680

 

Hence, the issue can be caused by register key since the system service needs to get related information from service register value first.

 

Root Cause

 

We found extra Environment value under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\, as below:

Windows Registry Editor Version 5.00

 

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC]

….

"Environment"=hex(7):00,00

 

Data of Environment value is empty.

 

We have reviewed OS source code, when system starts service, the environment value will be read by service if exists and merge into parent’s Environment value. If there is no environment value, the value will be inherited from parent node.  Then it is used by service starting procedure.

 

The issue can be reproduced after add Environment Multi-String Value with empty data under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\

 

Solution

Delete the Environment value under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\
Successfully start the
World Wide Web Publishing Service.

 

 

Enjoy!

 

Anik Shen

 

Posted by dsifof | 1 Comments

How does BizTalk detect if a host instance is dead in BTS2K6, 2K6R2 and 2K9?

 

This job is done by the cooperation between the front end BizTalk host instance process and the backend BizTalk SQL job MessageBox_DeadProcesses_Cleanup_BizTalkMsgBoxDb.  

1.       When a BizTalk host instance is started, it will call the store procedure bts_ProcessHeartbeat_<HostName> once as the below.

 

exec [dbo].[bts_ProcessHeartbeat_<HostName>] @uidProcessID=NULL,@dwCommand=1,@nHeartbeatInterval=60

 

Here @dwCommand=1 means Process Startup.

 

2.       When a BizTalk host instance is stopped, it will call the same store procedure bts_ProcessHeartbeat_<HostName> once again as the below.

 

exec [dbo].[bts_ProcessHeartbeat_<HostName>] @uidProcessID=NULL,@dwCommand=2,@nHeartbeatInterval=60

 

Here @dwCommand=2 means Process Shutdown.

 

3.       Look at the code of the store procedure bts_ProcessHeartbeat_<HostName>, could see the int_ProcessCleanup_<HostName> will be called if dwCommand=1(Process Startup) or dwCommand=2(Process Shutdown). The store procedure int_ProcessCleanup_<HostName> is used internally to clean up the records related with the host instance process and release all messages and service instances which are locked by this process.

 

4.       It is easy to understand why int_ProcessCleanup_<HostName> is called when a host instance is shutdown, the messages and service instances locked by the host instance can be freed before the shutdown so they can be picked up by the same restarted host instance again or they can be picked up by other host instances which are still running in a multiple boxes BizTalk environment.

 

5.       The questions is why int_ProcessCleanup_<HostName> is also called when a host instance is startup if the locked messages and services instances were already freed by the same SP when shutdown? Yes, it is redundant if the same SP was already called when the instance shutdown normally, but the problem is that the process could be terminated or crashed unexpectedly without calling the SP, You can see that abnormal shutdown easily by killing a host process, the SP bts_ProcessHeartbeat_<HostName> with the dwCommand=2 is not called if the host process is killed by the command “kill /f”. As we can’t guarantee the internal cleanup SP is already called before the host instance is started, to call the internal cleanup SP again at the startup is the good choice although it is redundant some times.

 

Another question is raised at this point, if a host instance process is totally hang or dead there, or it is just crashed or terminated unexpectedly without restarting, who can help to detect the situation and release these locked messages and service instances? How? Let’s continue.

 

6.       In each running BizTalk host instance, you can see one thread as the below.

 

0:016> kc

 

ntdll!NtWaitForSingleObject

kernel32!WaitForSingleObjectEx

kernel32!WaitForSingleObject

BTSMessageAgent!CAdminCacheRefresh::OnCall

BTSMessageAgent!CThreadPoolWrapper::ThreadWorker

ntdll!RtlpWorkerCallout

ntdll!RtlpExecuteWorkerRequest

ntdll!RtlpApcCallout

ntdll!RtlpWorkerThread

kernel32!BaseThreadStart

 

7. The thread calls the store procedure bts_ProcessHeartbeat_<HostName>  with @dwCommand=0 every 60 seconds by default. The interval can be modified through the column ConfigurationCacheRefreshInterval of the table adm_Group in BizTalkMGMTDb or through the settings of the BizTalk group in BizTalk admin UI.

 

exec [dbo].[bts_ProcessHeartbeat_Newhost] @uidProcessID=NULL,@dwCommand=0,@nHeartbeatInterval=60

 

Here @dwCommand=0 means Process Live.

 

8. Look at the code of the store procedure bts_ProcessHeartbeat_<HostName>, the internal SP int_ProcessCleanup_<HostName> will not be called if dwCommand=0(Process Live). The bts_ProcessHeartbeat_<HostName> will only update a record or insert a new record if there is no existing one in the table ProcessHeartbeats in BizTalkMsgBoxDb for the host instance.

 

9. Let’s look at the record in the table ProcessHeartbeats and see what it is look like.

 

uidProcessID

nvcApplicatioName

dtCreationTime

dtLastHeartbeatTime

dtLastHeartbeatTime

4d50992e-2ae1-4bbd-9d61-b712b052b99c

BizTalkServerApplication

11/25/2009 4:52:44 AM

11/25/2009 4:52:44 AM

11/25/2009 5:02:44 AM

uidProcessID is the unique GUID for each host instance. You can get the uidProcessID for a host instance by query the UniqueId column of the table adm_HostInstance in BizTalkMGMTDb. You also can get the uidProcessID for a host instance by checking the service property “Path to Executable” of the corresponding BizTalk service in Windows Service Control Manager on a BizTalk box. For example, the following is the “Path to Executable” setting for my "BizTalkServerApplication" in my BizTalk testing box. You can see the ID is after the command line option “-btsapp”.

 

"C:\Program Files (x86)\Microsoft BizTalk Server 2006\BTSNTSvc.exe" -group "BizTalk Group" -name "BizTalkServerApplication" -btsapp "{4D50992E-2AE1-4BBD-9D61-B712B052B99C}"

 

You can note that the dtNextHeartbeatTime is about equal to (dtLastHeartbeatTime+10*HeartbeatInterval). Since the default HeartbeatInterval is about 60 seconds by default(we mentioned how to modify that interval at the above), the dtNextHeartbeatTime is about 10 minutes after the dtLastHeartbeatTime by default. Of course if the HeartbeatInterval is modified to 30 seconds, then the dtNextHeartbeatTime would be 5 minutes after the dtLastHeartbeatTime.

 

10. Normally the record for a specified host instance in the table ProcessHeartbeat is updated every [HeartbeatInterval] seconds through the SP bts_ProcessHeartbeat_<HostName> by the running host instance process.

 

11. Take a look at the SQL job MessageBox_DeadProcesses_Cleanup_BizTalkMsgBoxDb, it is configured to execute the store procedure bts_CleanupDeadProcesses every minute.

 

12. Look at the code of the SP bts_CleanupDeadProcesses, it is simply go through the table ProcessHeartbeats and check if there is a host instance which dtNextHeartbeatTime is older than the current time. If there is, which means we already lost 10 heartbeats at least from this host instance, this host instance is then considered as dead and the store procedure int_ProcessCleanup_<HostName> for that instance is called by the SQL job to clean up the records related with the host instance process and release all messages and service instances which are locked by the process.

 

If this SQL job is disabled or get a problem when it is running, BizTalk will lost the capability to detect “dead” of a host instance.

 

Regards,

 

XiaoDong Zhu

 

 

 

Unable to suspend or terminate active service instance in Biztalk

 

Symptom

 

When try to suspend or terminate a active service instance, the instance can not be suspended or terminated for a long time, it keeps active with Pending Job of the instance is set to Suspend or Terminate

 

Analysis

 

A service instance is in Active status means that it is still actively running in a host instance and hasn’t reached the next persistence point. Suspend and Terminate operations are designed as operation which will only be executed at the next persistable point. The Suspend or Terminate operation will be put into the pending operation table when the target service instance is in Active status. Please note BizTalk only hold one pending operation for a single instance. The instance will keep Active status with the queued pending operation until the next persistence point is reached. Let’s use a simple orchestration example to demo the behavior.

biztalk1.JPG

biztalk2.jpg

 

The code is in Expression_1 is as the below which is used to simulate long time processing in a host instance or hang in a host instance.

 

System.Threading.Thread.Sleep(5*60000);

 

When drop a testing message to activate the above simple orchestration, it will keep Active status for about 5 minutes and then an output message will be sent out. If try to suspend the active instance when the instance is sleeping in the host instance,  the instance will keep in Active status for a quite while with Pending Job is set to Suspend until the next persistence point - send shape is reached. One interesting thing is that the orchestration instance will be started from the last persistence point to continue the execution if the running host instance is restarted, our simple orchestration will start from the beginning to re-execute the whole orchestration code again if the host instance is restarted during System.Threading.Thread.Sleep(),we will see the instance will keep Active status with the pending operation Suspend for another 5 minutes. Now we got a problem, If the code in the expression shape is changed as the below to simulate a real hang situation.

 

while(1==1){System.Threading.Thread.Sleep(5*60000);}

 

We will find we can’t suspend the Active instance. The orchestration instance will keep Active with the pending operation Suspend forever even if the running host instance is restarted in BTS 2K6 and 2K6R2.

 

The ways to handle a long time active or hang instance as the above

 

1.  The format way should be to find where is the instance active or hang. The HAT debugging or a hang dump file for the running host instance can be used to find out where the instance processing is blocked. If the processing block or the hang can be fixed, then the instance can quickly move to the next persistable point, the pending operation or the other operations can get a chance to execute.

 

2. If you don’t want to spend the time to figure out where the blocking is and just want to simply clean out the instance from the MessageBox, use the tool Terminator to terminate these instance hardly. You can download the Terminator from the below link. The following is the captured screen for Terminate Instance (Hard) for the reference.

 

http://blogs.msdn.com/biztalkcpr/pages/biztalk-terminator-download-install-info.aspx

biztalk3.JPG

3. As the above, if just want to suspend or terminate the instance, besides the Terminator, you also can call the internal store procedure int_AdminSuspendInstance_<host> or int_AdminTerminateInstance_<host> directly to suspend or terminate the instance in MessageBox database. The following are the two SQL script sample to use the two store procedures.

 

Hard Suspend:

 

declare @ApplicationName nvarchar(128)

declare @uidInstanceID uniqueidentifier

declare @uidServiceID uniqueidentifier

declare @fKnownInstance int

declare @nvcErrorString nvarchar(512)

declare @dtTimeStamp datetime

declare @spname nvarchar(512)

Begin Tran

set @ApplicationName='testhost'

set @uidInstanceID='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

set @uidServiceID='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

set @dtTimeStamp=GETUTCDATE()

select @nvcErrorString = nvcError FROM dbo.LocalizedErrorStrings WHERE nID = 4

set @spname= 'int_AdminSuspendInstance_' + @ApplicationName

exec @spname @uidInstanceID, @uidServiceID, N'0xC0C01B50', -1, @nvcErrorString, 1, null, @dtTimeStamp, null, null, @fKnownInstance OUTPUT

DELETE FROM InstancesPendingOperations WITH (ROWLOCK) WHERE uidInstanceID = @uidInstanceID OPTION (KEEPFIXED PLAN)

Commit Tran

 

Hard Terminate:

 

declare @ApplicationName nvarchar(128)

declare @uidInstanceID uniqueidentifier

declare @uidServiceID uniqueidentifier

declare @fKnownInstance int

declare @spname nvarchar(512)

Begin Tran

set @ApplicationName='testhost'

set @uidInstanceID=' xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx '

set @uidServiceID=' xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx '

set @spname= 'int_AdminTerminateInstance_' + @ApplicationName

exec @spname @uidInstanceID, @uidServiceID, @fKnownInstance OUTPUT

DELETE FROM InstancesPendingOperations WITH (ROWLOCK) WHERE uidInstanceID = @uidInstanceID OPTION (KEEPFIXED PLAN)

Commit Tran

 

*note*    

(1) The two store procedures are used by BizTalk internally to suspend or terminate an instance, the implementation and the SP interface could be changed in future. The above sample scripts are based on BTS2K6 and BTS2K6R2

(2) You must modify the script to provide the BizTalk Host name, the uidInstanceID and uidServiceID of the target service instance to the variables @ApplicationName, @uidInstanceID and @uidServiceID before execute the script.

(3) Stop the running host instance before execute the script in order to avoid any inconsistence error between the status of the running instance in the host process memory and the status of the instance persisted in the database.

*note* In multiple boxes BizTalk environment, the host instance which an active instance is running in can be found by looking “Processing Server” and “Host” columns of the service instance in BizTalk admin console. The columns for “Processing Server” and “Host” are not listed in the BizTalk group hub UI by default and they can be added manually.

(4) As you can see in Terminator when use Terminate Instance (Hard), the above script should also be used as a last resort. You should be very clear what you want to do and what the impact could be in business before decide to use the script.

 

4. In BTS2K6 R2 + KB969987 (http://support.microsoft.com/kb/969987) and BTS2K9, it is easier to terminate or suspend such active instance. If you see the instance keep Active with the Pending Operation set after terminate or suspend an active instance in BTS2K6 R2 + KB968897 and BTS2K9, simply restart the host instance which the target service instance is running with, you will see the Pending operation(Terminate or Suspend) got executed immediately after the host instance is restarted. This is because that when a host instance is restarted in BTS2K6 R2 + KB969987 or in BTS2K9, it will check if there is a Pending Operation for every service instance which was owned by this host instance previously, the Pending Operation for an instance will get executed immediately if it is found.

 

Regards,

 

XiaoDong Zhu

 

0x800706D9 when contact a SSO master secret cluster

 

 

Symptom:

==========

 

You may see the following warning event in a BizTalk machine.

 

Event Type: Warning

Event Source: ENTSSO

Event ID: 10536

Description:

SSO AUDIT

Function: GetConfigInfo

Tracking ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Client Computer: xxx.xxx.xxx (BTSNTSvc.exe:1234) Client User: Domain\BizAdmin Application Name: { xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx } Error Code: 0x800706D9, There are no more endpoints available from the endpoint mapper.

 

If try to backup the master secret on the SSO master secret cluster, you can get the below error:

 

C:\Program Files\Common Files\Enterprise Single Sign-On>ssoconfig -backupsecret test.bak
Password : *******
Confirm Password : *******
Password reminder : 1234567
ERROR: 0xC0002A0F : Could not contact the SSO server 'sso-cluster'. Check that SSO is configured and that the SSO service is running on that server.
(RPC: 0x800706D9: There are no more endpoints available from the endpoint mapper.)

 

Cause:

===========

In the SSO master secret cluster environment, the RPC service “SSOSecretServer” will not be registered successfully in the RPC endpoint mapper if the local ENTSSO service is started on a node before the clustered ENTSSO resource is brought online on this node.

 

For example, someone starts the local ENTSSO service from the service control manager or some tool executes a command “net start ENTSSO” on a cluster node.

 

In our case, we find there is a monitoring tool which periodically starts the local ENTSSO service on both cluster nodes if it finds they are not started, then the error will be reported when the cluster ENTSSO failover to another node which the local ENTSSO service is already started. Using “rpcdump” utility (the command “rpcdump -s <sso-cluster> -i”) or “portqry” utility (the command “portqry -n <sso-cluster> -e 135”) could list the registered RPC services in a RPC endpoint mapper. In this case, we only see the SSO related RPC services SSOMappingServer,SSOAdminServer,SSOLookupServer,SSOCSServer were registered but SSOSecretServer.

 

Solution:

=========

Stop the local ENTSSO service on another node and failover the cluster SSO to the node.

Configure the monitoring tool and stop to start the local ENTSSO service on both cluster nodes.

 

Regards,

 

XiaoDong Zhu

Why can't I retrieve metadata of WCF service to generate proxy class successfully?

 

Symptom:

When we use svcutil.exe to generate the proxy class or configuration file through retrieving published WCF service metadata, or we add service reference in IDE to reference to a WCF service, we may receive below error message.

“There is an error in the XML document.
The maximum nametable character count quota (16384) has been exceeded while reading XML data. The nametable is a data structure used to store strings encountered during XML processing - long XML documents with non-repeating element names, attribute names and attribute values may trigger this quota. This quota may be increased by changing the MaxNameTableCharCount property on the XmlDictionaryReaderQuotas object used when creating the XML reader.
If the service is defined in the current solution, try building the solution and adding the service reference again”

For example, suppose you have published a WCF service endpoint with net.tcp binding which metadata endpoint is deployed as follows:
net.tcp://WCFServer:88/yourService/MEX/

Then you use svcutil.exe to generate the proxy class and configuration file as follows:
Svcutil.exe net.tcp://WCFServer:88/yourService/mex/ /config:app.config /out:proxyclass.cs

You may receive above error message.

Root Cause & Solution:
When WCF client  retrieves the large service metadata to generate client proxy class, the threashold about MaxNameTableCharCount of XmlDictionaryReaderQuotas object which is 16384 bytes is trigged when processing the large metadata XML file, just as described in the error message.

In order to customize this threshold, we need to configure a configuration file manually to reset value of MaxNameTableCharCount for the WCF metadata retrieving tool, such as svcuti.exe, or IDE. That is to say,
     a)   For svcutil.exe, we need to create a corresponding configuration file called svcutil.exe.config ;

 b)   For Visual Studio2008, we need to create a corresponding configuration called devenv.exe.config.

Then add correct configuration section to the corresponding file and restart the tool.

a)       if your MEX endpoint is published with net.tcp binding, we could configure the endpoint with net.tcp binding as follows:

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <system.serviceModel>

    <client>

      <endpoint name="net.tcp" binding="netTcpBinding" bindingConfiguration="bc" contract="IMetadataExchange" />

    </client>

    <bindings>

      <netTcpBinding>

        <binding name="bc" maxReceivedMessageSize="512000">

          <readerQuotas maxNameTableCharCount="2147483647" />

          <security mode="None"/>

        </binding>

      </netTcpBinding>

    </bindings>

  </system.serviceModel>

</configuration>

 

b)      if your MEX endpoint is published with HTTP related binding, we could configure the endpoint with custom binding as follows:

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <system.serviceModel>

    <bindings>

      <customBinding>

        <binding name="MyBinding">

          <textMessageEncoding>

            <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"

                maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />

          </textMessageEncoding>

          <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />

        </binding>

      </customBinding>

    </bindings>

    <client>

      <endpoint binding="customBinding" bindingConfiguration="MyBinding"

          contract="IMetadataExchange"

          name="http" />

    </client>

  </system.serviceModel>

</configuration>

References:
XmlDictionaryReaderQuotas
http://msdn.microsoft.com/en-us/library/aa702595.aspx

<readerQuotas>
http://msdn.microsoft.com/en-us/library/ms731325.aspx

Best Regards,

Winston He.

 

Why does client application report “RPC is Unavailable” after compiled as a Release Version?

 

One customer has a DCOM application, which was developed by unmanaged C++. The client application is the managed code. When the client application is compiled as a Debug version, everything runs smoothly, however, after it runs as a Release version, an “RPC is Unavailable” happens always.

 

Analysis

==========

While we look at the issue, my first thought is that the DCOM server application crashes for some reason. We used debugging tool Adplus.vbs , and confirmed that the DCOM server application just exits normally without any exceptions.

 

In my opinion, another possible reason is that the DCOM objects has no references, then the DCOM server process quits accordingly by following its mechanism. For more regarding DCOM architecture and overview, please refer to:

 

DCOM Architecture

http://msdn.microsoft.com/en-us/library/ms809311.aspx

 

DCOM Technical Overview

http://msdn.microsoft.com/en-us/library/ms809340.aspx 

 

Why does the DCOM objects reference counter suddenly become Zero and why this only happens to Release mode?

 

We used the tttracer to capture the client application and DCOM server process. Found the client application hits the “RPC is unavailable” at this call stack:

 

0:001> !sos.clrstack

OS Thread Id: 0x55c (1)

ESP       EIP    

0012df48 79e7cc26 [GCFrame: 0012df48]

0012e150 79e7cc26 [GCFrame: 0012e150]

0012e35c 79e7cc26 [HelperMethodFrame_PROTECTOBJ: 0012e35c] System.RuntimeType.InvokeDispMethod(System.String, System.Reflection.BindingFlags, System.Object, System.Object[], Boolean[], Int32, System.String[])

0012e3e4 7928e3a2 System.RuntimeType.InvokeMember(System.String, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object, System.Object[], System.Reflection.ParameterModifier[], System.Globalization.CultureInfo, System.String[])

0012e530 0a4f6528 Mycomponent.UnisimMycomponent.AddStageDataWithLateBinding(System.Type, System.Object, System.Object)

0012e6bc 0a4f5ec0 Mycomponent.UnisimMycomponent.GetFlowDataWithLateBinding(System.Type, System.Object, Mycomponent.DataStructure.SimulationFile)

0012e71c 0a4f5af0 Mycomponent.UnisimMycomponent.GetSubFlowsWithLateBinding(System.Type, System.Object, System.Object, Mycomponent.DataStructure.SimulationFile, System.String)

0012e75c 0a4f5b26 Mycomponent.UnisimMycomponent.GetSubFlowsWithLateBinding(System.Type, System.Object, System.Object, Mycomponent.DataStructure.SimulationFile, System.String)

0012e79c 0a4f586a Mycomponent.UnisimMycomponent.AddUnisimSimFileWithLateBinding(Mycomponent.DataStructure.SimulationFile, System.String)

 

Based on the call stack, we double checked the related code, it is like this:

 

       object realVar = mytype.InvokeMember("myPropertyA", BindingFlags.GetProperty, null, stage, null);

        double val = (double) mytype.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, realVar, null);

 

The problem turns out to be a managed object that holds a pointer to an unmanged object and making a p/invoke with no further references to the object, after the p/invoke is garbage collected before the p/invoke is finished. In this case, because objects have not been referenced any more at this moment due to garbage collection in managed client application, then the DCOM server exited “smoothly”. Finally the “RPC is unavailable” error happens.

 

How to keep the unmanaged object reference while calling unmanaged object through P/Invoke, so that DCOM server process will not exit unexpectedly? The answer is we can use GC.KeepAlive().

 

The purpose of the KeepAlive method is to ensure the existence of a reference to an object that is at risk of being prematurely reclaimed by the garbage collector. A common scenario where this might happen is when there are no references to the object in managed code or data, but the object is still in use in unmanaged code such as Win32 APIs, unmanaged DLLs, or methods using COM.

 

The important thing is to code this KeepAlive method at the end, not the beginning, of the range of instructions where obj must be available.

 

Refer to:

http://msdn.microsoft.com/en-us/library/system.gc.keepalive.aspx

 

So why in debug mode we didn’t experience this issue? Chris’ blog has mentioned this point:

 

However if you compile the code in debug mode, the JIT will extend lifetimes of references to the end of their enclosing method.  In this case, KeepAlive actually isn’t necessary.  But in the release case, a reference should be live until the last line of code that references it.

 

Refer to:

http://blogs.msdn.com/clyon/archive/2006/08/28/728688.aspx

 

After customer followed the guideline to use KeepAlive, the application works well in Release Mode now.

 

Best Regards,


Freist Li

How to index IIS 7.0 Web sites in Windows Server 2008 by Indexing Service

 

If you follow the instructions in the article KB954822, you may find the web sites are still not indexed.

 

 

We can use the following steps:

 

Install IIS 6 Management Compatibility

=============================

 

1.            Click Start , point to All Programs , point to Administrative Tools , and then click Server Manager .

2.            In the console tree of Server Manager, Expand Roles , and then right click Web Server(IIS). Click Add Role Services

3.            In the Add Role Services Wizard, select IIS 6 Management Compatibility, and then click Next .

4.            Follow the instructions in the Add Role Services Wizard to complete the installation.

 

Select the web site you want to search

==============================

 

1.       In Indexing MMC right click your catalog and choose Properties.

2.       Click Tracking tab.

3.       Select the web site in “WWW Server” dropdown list.

4.       Then click OK.

5.       If you open the property page again, you will see that “WWW Server” field is still empty. But it is just a UI issue.

6.       To verify whether you select the web site, please check the following values under the registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex\Catalogs\[Catalog Name]

IsIndexingW3Svc

W3SvcInstance

                               

Make sure the value IsIndexingW3Svc is 1 and the value of W3SvcInstance is your selected web site instance.

 

Set ContentIndexed metabase property

================================

 

In Windows 2003 you can select the option “Index this resource” on the virtual directory if you want to index some web pages. But in Windows 2008 there is no administrative UI for you to enable this option. We have to use command line scripts:

1.       Open a command prompt and change the current directory to %systemdrive%\inetpub\adminscripts.

2.       Run the command: cscript adsutil.vbs set w3svc/[web site instance]/root/[virtual director]/ContentIndexed 1

 

For example, if you want to enable “Index this resource” on the virtual directory MyVIR of the default web site, you can run: cscript adsutil.vbs set w3svc/1/root/MyVIR/ContentIndexed 1

 

After you enable the above options, you can restart your indexing service. The indexing service will automatically check the IIS settings and generate the catalog.

 

Regards,

 

Xin Jin

 

 

Posted by dsifof | 0 Comments
More Posts Next page »
 
Page view tracker