Batch to Logging Worker Process Recycling Events in IIS 6.

I want to log Worker Process Recycling Events in IIS 6.0 (IIS 6.0) , but ther is no UI for this.
I’ve created batch file and decided to post it here, because current instructions have a few typos.
You should modify value of AppPoolName as appropriate.


:rem IISLoggingWorkerProcessRecycling.bat
:rem from http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/87892589-4eda-4003-b4ac-3879eac4bf48.mspx?mfr=true
set EnableEvent=true
set AppPoolName=ASP.NET v2.0
%systemDRIVE%
cd %systemDRIVE%inetpubadminscripts
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleTime” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleRequests” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleSchedule” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleMemory” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleIsapiUnhealthy” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleOnDemand” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleConfigChange” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecyclePrivateMemory” %EnableEvent%


 

Call Web Services through SQuid proxy server with authentication requested

My ASP.NET application calls web services( including Google Web API) and it is a requirement to access it through Proxy Server that requires Authentication. It works correctly with Microsoft ISA server (see my post Set defaultProxy configuration Element for Proxy Server) .


But it didn’t work with Squid proxy server Authentication.


When I specified useDefaultCredentials=true, the WebException returned : “HTTP status 417: Unknown“.
After some investigation I found that 417 is actually Expectation failed and then that MS Web Services have HttpWebRequest and the Expect: 100-continue Header Problem .
So I had to override GetWebRequest for Web Services to set Expect100Continue = false and requests are going through Squid proxy server.Hurray!


using System.Net;



namespace Google_Web_APIs_Demo.Google


{


    public partial class GoogleSearchService//: System.Web.Services.Protocols.SoapHttpClientProtocol


    {


        protected override WebRequest GetWebRequest(Uri uri)


        {


           WebRequest wr= base.GetWebRequest(uri);


           HttpWebRequest wrHttp = wr as HttpWebRequest;


           if (wrHttp != null)


               wrHttp.ServicePoint.Expect100Continue = false;//avoid expects error http://haacked.com/archive/2004/05/15/449.aspx


           return wr;


        }


    }


}


 UPDATE: The behavior could be changed in config file:





 


<configuration>


<system.net>


<settings>


            <servicePointManager expect100Continue=”false” />


</settings>


</system.net>


</configuration>


            





 UPDATE: Slightly related problem:
If you have error: “The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF”, add
add in the web.config the following (in brown)  (from http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=21106&SiteID=1&PageID=0 )


<configuration>
 <system.net>
 <settings>
 <httpWebRequest useUnsafeHeaderParsing=”true” />
 </settings>
 </system.net>
 </configuration>


Update: the solution described above helped for one client with Squid, but din’t help on another site.

Handling missing source columns in DataSetHelper.InsertInto method

I am using a DataSetHelper class from MS kb article 326009 HOW TO: Implement a DataSet SELECT INTO Helper Class in Visual C# .NET 


Recetly I’ve noticed that InsertInto method throws exception if the source table doesn’t have some columns from the target. It will be better to set columns to null or default.


The changed code is the following:


            ///


            /// Sample of call


            /// dsHelper.InsertInto(ds.Tables[“TestTable”], ds.Tables[“Employees”], “FirstName FName,LastName LName,BirthDate”, “EmployeeID<5”, “BirthDate”) ;


            ///


            public void InsertInto(DataTable DestTable, DataTable SourceTable,


                  string FieldList, string RowFilter, string Sort)


            {


                  //


                  // This code copies the selected rows and columns from SourceTable and inserts them into DestTable.


                  //


                  ParseFieldList(FieldList, false);


                  DataRow[] Rows = SourceTable.Select(RowFilter, Sort);


                  DataRow DestRow;


                  foreach(DataRow SourceRow in Rows)


                  {


                        DestRow = DestTable.NewRow();


                        if (DataHelper.IsNullOrEmpty(FieldList))


                        {


                    foreach (DataColumn dc in DestRow.Table.Columns)


                    {


                        if (dc.Expression == “”)


                        {


                            if (SourceTable.Columns.Contains(dc.ColumnName))//source can miss some target columns


                                DestRow[dc] = SourceRow[dc.ColumnName];


                            else


                                DebugHelper.LineWithTrace(“The column is missing in the source:” + dc.ColumnName);


                        }


                    }


                        }


                        else


                        {


                              foreach(FieldInfo Field in m_FieldInfo)


                              {


                                    DestRow[Field.FieldAlias] = SourceRow[Field.FieldName];


                              }


                        }


                        DestTable.Rows.Add(DestRow);


                  }


            }


 


 

Retry to call Web Service in case of “The remote name could not be resolved” error.

I found that sometimes, if I have an error “The remote name could not be resolved” to access remote web services, I should re-try the call and it helps.
I’ve considered to increase timeout for WebServices method call, but some methods,e.g. DataSet.ReadXml (String)  doesn’t have the option.

So I’ve created a static method that will retry remote call a few times. The actual function to call can be passed as delegate:

    public class WSClientHelper

    {

        public delegate void CallWebServiceDelegate ();

        public static void RetryWebServiceCall(int nRetry, CallWebServiceDelegate dlgt)

        {         // I beleive that it’s a good idea to re-try in case of “The remote name could not be resolved”

                for (int i = 0; i < nRetry; i++)

                {

                    try

                    {

                        dlgt();// ds = ReadRssUrlAsDataSet(timeStart, url);

                        break;

                    }

                    catch (WebException exc)

                    {

                        if (exc.Message.Contains(“The remote name could not be resolved”) && (i < nRetry-1))

                        {  DebugHelper.TracedLine(“Attempt “ + i.ToString() + ” failed.” +exc.Message);

                            continue;//try n times

                        }

                        throw;

                    }

                }

        }

    }

 

The sample to use utilizes C# anonymous delegates(new for .Net 2.0), which makes the use very compact and simple

                FSCSharpLib.ASP.WSClientHelper.RetryWebServiceCall(3, delegate

                {

//Yo can put any code you like with unrestricted access to local variables and class members

                    ds = ReadRssUrlAsDataSet(timeStart, url); //just sample method

                });

 

The StackOverflow question http://stackoverflow.com/questions/1563191/c-sharp-cleanest-way-to-write-retry-logic/1563234#1563234 discuss similar approach.

GridView with inline inserts -different implementations.

I wanted to use GridView with inline inserts capability. Unfortunately it is not available out-of-the-box.


 I found Code Project’s “ASP.NET GridView – Add a new record“ , but I don’t like an idea to create dummy empty row as the first line in the DataSource. Another Code Project’s GridView Redux article seems uses the same approach.


I’ve tried Real World GridView” , but it  doesn’t  populate DropDownField with the List Values for  Insert rows.


The most promising looks Fredrik Normén’s  Use the GridView to insert a new record .


I haven’t tryed yet Code Project’s An extended GridView that allows inserting rows 

Editable GridView with ObjectDatasource and Update method parameters.

Recently I posted Some workaround for ObjectDataSource: could not find a non-generic method ‘…’ .
Sinse that I done some investigation to understand better the reason of the problem and possible workarounds. Most of them are posted in thread “Dataset + ObjectDatasource + GridView + ASP.NET 2” .
The problem  perfectly described here. And it is reported to MS, but they don’t want to address it.


Actually Update code trying to executeby ASP.NET  from ObjectDataSource very depends on fields and field properties, declared in GridView.
If field has ReadOnly=true or Visible=false, it is not expected as a parameter to Update method and causes the error
System.InvalidOperationException: ObjectDataSource ‘…’ could not find a nongeneric method ‘Update’ that has parameters: ….
The reason is that readonly and invisible properties are not stored in ViewState and are not available on the time of Update parameters are populated.( I beleive that MS could extract read-only fields data to submit to pass as Update parameters, but they do not in this version).
Detailed description about ObjectDataSources parameters can be found in Manuel Abadia’s blog.


So my approach is the following (in general following the tutorial “Working with Data in ASP.NET 2.0 :: An Overview of Inserting, Updating, and Deleting Data”  )  :
1.  Create the TableAdapters in the DAL (see Creating a Data Access Layer tutorial)


2.On the ASPX/ASCX page create ObjectDataSource and GridView.


3.Customize the GridView fields to specify the properties as ReadOnly,Visible=false, DataKey as required by busuness/UI requirements.


4. Run it and test inline Update method. It will return “could not find a non-generic method ‘Update’ that has parameters” error, which will list names and order of parameters that are required by gridview settings.


5. Return to strongly-typed dataset  XSD designer and add new Update adapter method with the parameters that gridView expects.
6. In ObjectDataSource change Update method to the new adaptor Update method. 


Update: I’ve posted related “Why we are getting ObjectDataSource: could not find a non-generic method ‘Update'”