Toggle Paging Mode in ASP.Net GridView

February 24, 2012

Customers requested the possibility to toggle the display of data in a GridView between paged view and complete view. I sketch a method to add a LinkButton in the Pager rows that performs this toggle.

A GridView’s pager row is rendered in HTML as

<tr>
  <td colspan="7">                   <-- the number of columns in the grid
    <table border="0">
      <tbody><tr>
        <td><span>1</span></td>
        <td><a href="javascript:__doPostBack('GridView1','Page$2')">2</a></td>
        ... etc for each page ...
      </tr></tbody>
    </table>
  </td>
</tr>

My approach is to insert the LinkButton right to the table containing the page selectors, by injecting a right-floating span before the page selector table in GridView_RowCreated:

protected void GridView_RowCreated(object sender, GridViewRowEventArgs e)
{
  var gv = sender as GridView;

  switch (e.Row.RowType)
  {
    case DataControlRowType.Pager:
      TableCell cell = e.Row.Cells[0];
      Table tbl = (Table)cell.Controls[0];
      cell = tbl.Rows[0].Cells[0];

      var span = new HtmlGenericControl("span");
      span.Attributes["style"] = "position:relative; float:right";
      span.Attributes["align"] = "right";
      span.Controls.Add(new Literal 
        { Text = "<table border=\"0\"><tbody><tr><td>" });
      LinkButton btnPaging = new LinkButton
        { Text = IsPaging(gv) ? "All Records" : "Paged View" };
      btnPaging.Click += new EventHandler(btnPaging_Click);
      span.Controls.Add(btnPaging);
      span.Controls.Add(new Literal 
        { Text = "</td></tr></tbody></table>" });
      cell.Parent.Parent.Parent.Controls.AddAt(0, span);
      break;

To find out which mode a GridView is rendering, we need a little helper function

bool IsPaging(GridView gv)
{
  return gv.PageSize <= 100;
}

Clicking the LinkButton will now toggle the paging mode, and we also save the PageSize to restore the previous value when clicking again:

void btnPaging_Click(object sender, EventArgs e)
{
  var gv = ((LinkButton)sender).Parent.Parent
    .Parent.Parent.Parent as GridView;
  if (IsPaging(gv))
  {
    gv.Attributes["pagesize"] = gv.PageSize.ToString();
    gv.PageSize = 100000;
    gv.PageIndex = 0;
  }
  else
  {
    gv.PageSize = deviolib.Convert.ToIntDef(gv.Attributes["pagesize"], 20);
  }
}

When I worked out this solution, I found that if the result displays in a single page, the pager is not displayed anymore. This answer on SO showed how to make it visible again: In the GridView_PreRender event, set both PagerRows’ Visible value.

void GridView_PreRender(object sender, EventArgs e)
{
  var gv = ((GridView)sender);

  GridViewRow pagerRow = gv.TopPagerRow;
  if (pagerRow != null && pagerRow.Visible == false)
    pagerRow.Visible = true;

  pagerRow = gv.BottomPagerRow;
  if (pagerRow != null && pagerRow.Visible == false)
    pagerRow.Visible = true;
}

MSSQL Legacy Data Types in NHibernate.Mapping.ByCode.Conformist

February 24, 2012

Trying to migrate the code generation of NHibernate data classes and mappings from 2.1.2 to 3.2 and from Fluent to Mapping ByCode Conformist, I noticed a couple of problems relating mostly to non-Unicode string fields and legacy data types such as image and ntext.

Typically, column mapping uses the Property() method for columns like to NVARCHAR column:

public partial class Application_Map: ClassMapping<Application>
{
  public Application_Map()
  {
    Property(x => x.ID, map =>
      {
        map.Column("ID");
        map.NotNullable(true);
        map.Length(100);
      });
  }
}

This kind of declaration raised a HibernateException for VARCHAR columns  in configuration.BuildSessionFactory()

Wrong column type in MyDatabase.dbo.Foo for column Bar. Found: varchar, Expected NVARCHAR(256)

To fix this exception, the varchar column needs to be declared like this:

  Property(x => x.VarcharFoo, map =>
    {
      map.Column(c =>
        {
          c.Name("VarcharFoo");
          c.SqlType("varchar");
          c.Length(50);
        });
    });

Similarly, we can declare the native SQL data type for image and ntext columns:

  Property(x => x.FooImage, map =>
    {
      map.Column(c =>
        {
          c.Name("FooImage");
          c.SqlType("image");
        });
      map.Lazy(true);
    });
  Property(x => x.FooNText, map =>
    {
      map.Column(c =>
        {
          c.Name("FooNText");
          c.SqlType("ntext");
        });
    });


Generating NHibernate Access to MSSQL Stored Procedures

February 23, 2012

This series describes the generation of C# classes and database access for NHibernate 2.1.2GA.

To store the information on which Stored Procedures to script out, we need a table Meta_Procedure, similar to Meta_Table presented earlier.

CREATE TABLE [dbo].[Meta_Procedure](
  [OID] [int] IDENTITY(1,1) NOT NULL,
  [ID] [nvarchar](50) NOT NULL,
  [UseDAL] [bit] NOT NULL,
  CONSTRAINT [PK_Meta_Procedure] PRIMARY KEY CLUSTERED
  ( [OID] ASC )
)

We fill this table from the list of stored procedures stored in sys.objects:

INSERT INTO Meta_Procedure (ID)
SELECT o.name
FROM sys.objects o
LEFT OUTER JOIN Meta_Procedure t ON o.name = t.id
WHERE o.type IN ('P')
AND t.OID IS NULL;

The developer now only needs to set the UseDAL field to true (1) for each procedure to be scripted.

Declaration of stored procedures for NHibernate consists of two parts: a .hbm.xml containing named queries with a TSQL statement to invoke each stored procedure, which is compiled as Embedded Resource:

CREATE PROCEDURE [dbo].[dev_Generate_DAL_HBM_XML] AS

  PRINT '<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    assembly="My.Project" namespace="My.Project.DAL">'
  
  DECLARE @oid INT, @id NVARCHAR(50)

  DECLARE cT CURSOR FOR
  SELECT object_id, name
  FROM sys.procedures p
  INNER JOIN Meta_Procedure mp ON p.name = mp.ID
  WHERE mp.UseDAL = 1
  ORDER BY name

  OPEN cT
  FETCH cT INTO @oid, @id

  WHILE @@FETCH_STATUS = 0 BEGIN
    DECLARE @cid NVARCHAR(50), @datatype NVARCHAR(50), 
      @isoutput BIT, @parameterid INT
    
    DECLARE cP cursor FOR
    SELECT  REPLACE(p.name, '@', ''), t.name, p.is_output, p.parameter_id
    FROM  sys.parameters p
    INNER JOIN sys.types t ON p.user_type_id = t.user_type_id
    WHERE   p.object_id = @oid
    ORDER BY p.parameter_id

    PRINT '    <sql-query name="' + @id + '" callable="true">'

    OPEN cP
    FETCH cP INTO @cid, @datatype, @isoutput, @parameterid

    WHILE @@FETCH_STATUS = 0 BEGIN
      IF @datatype = 'nvarchar' 
        SET @datatype = 'string'
      ELSE IF @datatype = 'date'
        SET @datatype = 'DateTime?'
      ELSE
        SET @datatype = @datatype + '?'

      PRINT '        <query-param name="' + @cid + '" type="' + @datatype + '" />'
      
      FETCH cP INTO @cid, @datatype, @isoutput, @parameterid
    END

    CLOSE cP

    PRINT 'begin'
    PRINT '    execute ' + @id 
    
    OPEN cP
    FETCH cP INTO @cid, @datatype, @isoutput, @parameterid

    WHILE @@FETCH_STATUS = 0 BEGIN
      IF @datatype = 'nvarchar' 
        SET @datatype = 'string'
      ELSE IF @datatype = 'date'
        SET @datatype = 'DateTime?'
      ELSE
        SET @datatype = @datatype + '?'

      IF @parameterid = 1
        PRINT '        :' + @cid
      ELSE BEGIN
        PRINT '        , :' + @cid
      END
      
      FETCH cP INTO @cid, @datatype, @isoutput, @parameterid
    END
    CLOSE cP

    DEALLOCATE cP
    
    PRINT 'end'
    PRINT '    </sql-query>'
    
    FETCH cT into @oid, @id
  END

  CLOSE cT
  DEALLOCATE cT

  PRINT '</hibernate-mapping>'

For each stored procedure, we need a C# method which calls the corresponding named query. The SP’s parameters are retrieved from the sys.parameters catalog view, and their data types translated just as we handled table columns.

CREATE PROCEDURE [dbo].[dev_Generate_DAL_Procedures] AS

  PRINT 'using System;'
  PRINT 'using System.Collections;'
  PRINT 'using NHibernate;'
  PRINT ''
  PRINT 'namespace My.Project.DAL'
  PRINT '{'
  PRINT '    public static class Procedures'
  PRINT '    {'
  
  DECLARE @oid INT, @id NVARCHAR(50)

  DECLARE cT CURSOR FOR
  SELECT object_id, name
  FROM sys.procedures p
  INNER JOIN Meta_Procedure mp ON p.name = mp.ID
  WHERE mp.UseDAL = 1
  ORDER BY name

  OPEN cT
  FETCH cT INTO @oid, @id

  WHILE @@FETCH_STATUS = 0 BEGIN
    DECLARE @cid NVARCHAR(50), @datatype NVARCHAR(50), @isoutput BIT
    
    DECLARE cP cursor FOR
    SELECT  REPLACE(p.name, '@', ''), t.name, p.is_output
    FROM  sys.parameters p
    INNER JOIN sys.types t ON p.user_type_id = t.user_type_id
    WHERE   p.object_id = @oid
    ORDER BY p.parameter_id

    PRINT '        public static IList ' + @id + '(ISession session'

    OPEN cP
    FETCH cP INTO @cid, @datatype, @isoutput

    WHILE @@FETCH_STATUS = 0 BEGIN
      IF @datatype = 'nvarchar' 
        SET @datatype = 'string'
      ELSE IF @datatype = 'date'
        SET @datatype = 'DateTime?'
      ELSE
        SET @datatype = @datatype + '?'

      PRINT '            , ' + 
        CASE WHEN @isoutput = 1 THEN 'out ' ELSE '' END + 
        @datatype + ' ' + @cid
      
      FETCH cP INTO @cid, @datatype, @isoutput
    END

    PRINT '            )'
    PRINT '        {'
    PRINT '            IQuery sp = session.GetNamedQuery("' + @id + '");'

    CLOSE cP

    OPEN cP
    FETCH cP INTO @cid, @datatype, @isoutput

    WHILE @@FETCH_STATUS = 0 BEGIN
      IF @datatype = 'nvarchar' 
        SET @datatype = 'string'
      ELSE IF @datatype = 'date'
        SET @datatype = 'DateTime?'
      ELSE
        SET @datatype = @datatype + '?'

      IF @datatype = 'string'
        PRINT '            sp.SetParameter<' + @datatype + 
          '>("' + @cid + '", ' + @cid + ');'
      ELSE BEGIN
        PRINT '            sp.SetParameter<' + @datatype + 
          '>("' + @cid + '", ' + @cid + ');'
      END
      
      FETCH cP INTO @cid, @datatype, @isoutput
    END
    CLOSE cP

    DEALLOCATE cP
    
    PRINT '            return sp.List();'
    PRINT '        }'
    
    FETCH cT INTO @oid, @id
  END

  CLOSE cT
  DEALLOCATE cT

  PRINT '    }'
  PRINT '}'

Benutzermittelschnur

February 20, 2012

Dear Machine Translation Industry start-ups,

Benutzermittelschnur” is not a valid, recognized, or intuitively parsable translation of “User Agent String”.

Google Translate leaves the English term untranslated as “User-Agent-String”.

Bing proposes “Zeichenfolge des Benutzer-Agents” which is recognizable if you know that the W3C uses “User Agent” as technical term for browsers.

Next lesson: “die Benutzermittelschnur schnüffeln


Generating NHibernate Classes for MSSQL in TSQL (2)

February 20, 2012

After retrieving the necessary meta data on tables and columns, we can now generate the C# classes for NHibernate and the necessary mapping information.

CREATE PROCEDURE [dbo].[dev_Generate_DAL_Classes] AS

  SET NOCOUNT ON

  PRINT 'using System;'
  PRINT 'using System.Collections.Generic;'
  PRINT 'using System.Linq;'
  PRINT 'using System.Text;'
  PRINT 'using System.ComponentModel;'
  PRINT 'using System.Runtime.Serialization;'
  PRINT 'using NHibernate.Validator.Constraints;'
  PRINT ''
  PRINT 'namespace My.Project.DAL'
  PRINT '{'

  DECLARE @oid INT, @id NVARCHAR(50), @tabletype NVARCHAR(1)

  DECLARE cT CURSOR FOR
  SELECT OID, ID, TableType
  FROM Meta_Table
  WHERE UseDAL = 1
  ORDER BY ID

  OPEN cT
  FETCH cT INTO @oid, @id, @tabletype

  WHILE @@FETCH_STATUS = 0 BEGIN
    PRINT '    public partial class ' + @id
    PRINT '    {'

    DECLARE @cid NVARCHAR(50), @datatype NVARCHAR(50), @length INT,
      @isnullable BIT, @isidentity BIT, @lookup NVARCHAR(50)

    DECLARE cC CURSOR FOR
    SELECT ID, DataType, Length, IsNullable, IsIdentity, LookupTable
    FROM   Meta_Column
    WHERE  Tbl_OID = @oid
    AND    IsActive = 1
    ORDER BY Seq

    OPEN cC
    FETCH cC INTO @cid, @datatype, @length, @isnullable,
      @isidentity, @lookup

    WHILE @@FETCH_STATUS = 0 BEGIN
      IF @datatype = 'nvarchar'
        SET @datatype = 'string'
      ELSE IF @datatype = 'varchar'
        SET @datatype = 'string'
      ELSE IF @datatype = 'date'
        SET @datatype = 'DateTime'
      ELSE IF @datatype = 'datetime'
        SET @datatype = 'DateTime'
      ELSE IF @datatype = 'bit'
        SET @datatype = 'bool'
      ELSE IF @datatype = 'varbinary' BEGIN
        SET @datatype = 'byte[]'
        SET @isnullable = 0
      END

      IF @isidentity = 1 OR @cid = 'OID'
        PRINT '        public virtual ' + @datatype + ' '
          + @cid + ' { get; private set; }'
      ELSE IF @lookup IS NOT NULL BEGIN
        IF @isnullable = 0
          PRINT '        [NotNull]'
        PRINT '        public virtual ' + @lookup + ' '
          + REPLACE(@cid, '_OID', '') + ' { get; set; }'
      END ELSE BEGIN
        IF @datatype = 'string' BEGIN
          IF @isnullable = 0
            PRINT '        [NotNullNotEmpty]'
          IF @length IS NOT NULL
            PRINT '        [Length('
              + CONVERT(NVARCHAR, @length) + ')]'
        END ELSE
          IF @isnullable = 1
            SET @datatype = @datatype + '?'

        PRINT '        public virtual ' + @datatype + ' '
          + @cid + ' { get; set; }'
      END
      FETCH cC INTO @cid, @datatype, @length, @isnullable,
        @isidentity, @lookup
    END

    CLOSE cC
    DEALLOCATE cC

    PRINT '    }'

    FETCH cT INTO @oid, @id, @tabletype
  END

  CLOSE cT
  DEALLOCATE cT

  PRINT '}'

This stored procedure generates a C# class for each of the tables with the UseDAL flag set to true by the developer. For the columns, the SQL Server data types need to be translated into C# (i.e. .Net data types)

And now for the Class Maps

CREATE PROCEDURE [dbo].[dev_Generate_DAL_ClassMaps] AS

  SET NOCOUNT ON

  PRINT 'using System;'
  PRINT 'using System.Collections.Generic;'
  PRINT 'using System.Linq;'
  PRINT 'using System.Text;'
  PRINT 'using FluentNHibernate.Mapping;'
  PRINT 'using NHibernate.Validator.Constraints;'
  PRINT ''
  PRINT 'namespace My.Project.DAL'
  PRINT '{'

  DECLARE @oid INT, @id NVARCHAR(50), @tabletype NVARCHAR(1)

  DECLARE cT CURSOR FOR
  SELECT OID, ID, TableType
  FROM Meta_Table
  WHERE UseDAL = 1
  ORDER BY ID

  OPEN cT
  FETCH cT INTO @oid, @id, @tabletype

  WHILE @@FETCH_STATUS = 0 BEGIN
    PRINT '    public partial class ' + @id + '_Map: ClassMap<' + @id + '>'
    PRINT '    {'
    PRINT '        public ' + @id + '_Map()'
    PRINT '        {'
    PRINT '            Table("' + @id + '");'

    DECLARE @cid NVARCHAR(50), @datatype NVARCHAR(50), @length INT,
      @isnullable BIT, @isidentity BIT, @lookup NVARCHAR(50)

    DECLARE cC CURSOR FOR
    SELECT ID, DataType, Length, IsNullable, IsIdentity, LookupTable
    FROM  Meta_Column
    WHERE  Tbl_OID = @oid
    AND    IsActive = 1
    ORDER BY Seq

    OPEN cC
    FETCH cC INTO @cid, @datatype, @length, @isnullable,
      @isidentity, @lookup

    WHILE @@FETCH_STATUS = 0 BEGIN
      IF @datatype = 'nvarchar'
        SET @datatype = 'string'
      ELSE IF @datatype = 'varchar'
        SET @datatype = 'string'
      ELSE IF @datatype = 'date'
        SET @datatype = 'DateTime'
      ELSE IF @datatype = 'datetime'
        SET @datatype = 'DateTime'
      ELSE IF @datatype = 'bit'
        SET @datatype = 'bool'
      ELSE IF @datatype = 'varbinary'
        SET @datatype = 'byte[]'

      IF @isidentity = 1
        PRINT '            Id(x => x.' + @cid + ').GeneratedBy.Identity();'
      ELSE IF @cid = 'OID'
        PRINT '            Id(x => x.' + @cid + ');'
      ELSE IF @cid = 'DateCreated'
        PRINT '            Map(x => x.' + @cid + ').Generated.Insert();'
      ELSE BEGIN
        IF @lookup IS NOT NULL BEGIN
          PRINT '            References(x => x.' +
              REPLACE(@cid, '_OID', '') + ', "' + @cid + '")' +
            CASE WHEN @isnullable = 0 THEN '.Not.Nullable()' ELSE '' END +
            '.LazyLoad();'
        END ELSE BEGIN
          PRINT '            Map(x => x.' + @cid + ')' +
            CASE WHEN @isnullable = 0 THEN '.Not.Nullable()' ELSE '' END +
            ';'
        END
      END
      FETCH cC INTO @cid, @datatype, @length, @isnullable,
        @isidentity, @lookup
    END

    CLOSE cC
    DEALLOCATE cC

    PRINT '        }'
    PRINT '    }'

    FETCH cT INTO @oid, @id, @tabletype
  END

  CLOSE cT
  DEALLOCATE cT

  PRINT '}'

These stored procedures can be invoked from the command line using the SQL Server osql tool

set osql=osql -S localhost -U [user] -P [pwd] -d [database] -n -w 1000
%osql% -Q "exec dev_Generate_DAL_Classes" -o "d:\path\to\Classes.cs"
%osql% -Q "exec dev_Generate_DAL_ClassMaps" -o "d:\path\to\ClassMaps.cs"

Generating NHibernate Classes for MSSQL in TSQL

February 19, 2012

This series describes the generation of C# classes and database access for NHibernate 2.1.2GA and FluentNHibernate 1.0. These are not the most current versions, but I need to document my existing code to prepare support of current versions of these libraries. I have previously written about NHibernate accessing Oracle in various post.

We generate the C# classes from the meta model contained in SQL Server system catalog views. However, generation does not directly access the catalog views, but caches information in meta tables that can hold additional information on tables and columns:

CREATE TABLE [dbo].[Meta_Table](
    [OID] [int] IDENTITY(1,1) NOT NULL,
    [ID] [nvarchar](50) NOT NULL,
    [TableType] [varchar](1) NOT NULL,
    [UseDAL] [bit] NOT NULL,
    CONSTRAINT [PK_Meta_Table] PRIMARY KEY CLUSTERED 
    ( [OID] ASC )
)
CREATE TABLE [dbo].[Meta_Column](
    [OID] [int] IDENTITY(1,1) NOT NULL,
    [Tbl_OID] [int] NOT NULL,
    [IsActive] [bit] NOT NULL,
    [Seq] [int] NOT NULL,
    [ID] [nvarchar](50) NOT NULL,
    [DataType] [varchar](50) NOT NULL,
    [Length] [int] NULL,
    [IsNullable] [bit] NOT NULL,
    [IsIdentity] [bit] NOT NULL,
    [LookupTable] [nvarchar](50) NULL,
    CONSTRAINT [PK_Meta_Column] PRIMARY KEY CLUSTERED 
    ( [OID] ASC )
) 

These tables are filled from the system catalog views using the following stored procedure

CREATE PROCEDURE [dbo].[dev_Retrieve_Meta] AS

  SET NOCOUNT ON;

  INSERT INTO Meta_Table (ID, TableType)
  SELECT o.name, o.type
  FROM sys.objects o
  LEFT OUTER JOIN Meta_Table t ON o.name = t.ID
  WHERE o.type IN ('V', 'U')
  AND t.OID IS NULL  ;

  UPDATE Meta_Column SET IsActive = 0;

  INSERT INTO Meta_Column (Tbl_OID, Seq, ID, DataType)  
  SELECT t.OID, c.clumn_id, c.name, ty.name 
  FROM sys.objects o
  INNER JOIN Meta_Table t ON o.name = t.ID
  INNER JOIN sys.columns c ON o.object_id = c.object_id
  INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
  LEFT OUTER JOIN Meta_Column mc 
    ON mc.Tbl_OID = t.OID AND mc.ID = c.name
  WHERE mc.OID IS NULL;

  UPDATE Meta_Column
  SET Seq = c.column_id, 
    DataType = ty.name, 
    Length = 
      CASE WHEN ty.name IN ('varchar', 'nvarchar') 
          AND c.max_length > -1 
        THEN c.max_length 
        ELSE NULL 
      END,
    IsNullable = c.is_nullable, 
    IsIdentity = c.is_identity,
    LookupTable = lt.name,
    IsActive = 1
  FROM Meta_Column mc
  INNER JOIN meta_table t ON mc.Tbl_OID = t.OID 
  INNER JOIN sys.objects o ON o.name = t.ID
  INNER JOIN sys.columns c 
    ON o.object_id = c.object_id AND mc.ID = c.name
  INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
  LEFT OUTER JOIN sys.foreign_key_columns fkc 
    ON fkc.parent_object_id = o.object_id 
    AND fkc.parent_column_id = c.column_id
  LEFT OUTER JOIN sys.objects lt 
    ON fkc.referenced_object_id = lt.object_id

The first INSERT statement retrieves all tables and views which are not already stored in the Meta_Table table.

Next, the new column names are retrieved from the sys.columns catalog view, and the columns’ IsActive field is set to false.

Finally, the UPDATE Meta_Column retrieves the column attributes from the catalog view, and sets the IsActive field to true for all columns still present in the catalog view (this is necessary to deal with changes in the data model).


User Interface Design

February 19, 2012

Comparing an Apple product, a Google product, and your product…

(When I was searching for this image, I really thought I had seen it on xkcd. It’s actually from stuffthathappens.com which is currently unavailable, so I save it for posterity ;) )


Test if Directory exists in Batch file (.cmd)

February 16, 2012

My previous post on testing network drives led me to further research the topic, and I came to quite surprising (at least for me) results: the result if a check with IF EXIST depend on whether

  • the drive is a local drive or a mapped network drive or a UNC path
  • the path contains spaces or not
  • the path is quoted or not
  • cmd runs in administrator mode or user mode

I wrote a small batch file that contains a couple of assignments of the form

set dir=c:\temp
set dir=c:\temp\with spaces
etc.

and executed these tests on each value

if exist %dir% echo exists
if exist %dir%\nul echo exists
if exist %dir%\. echo exists
if exist "%dir%" echo exists
if exist "%dir%\nul" echo exists
if exist "%dir%\." echo exists

These are the results

directory %dir% %dir%\nul %dir\. “%dir%” “%dir%\nul” “%dir%\.”
local x x x x x
local (spaces) - - - x x
mapped (non-admin) x x x x x
mapped (non-admin, spaces) - - - x x
UNC x x x x x x
UNC (spaces) - - - x x x

Comments:

Testing directory path containing spaces can only be performed using the quoted notation.

Mapped network drives can only be access in non-administrator mode (see these threads).

The only reliable way to test for directory existence is therefore to use the quoted “%dir%\.” notation.

To check whether cmd runs in administrator mode or not, use an admin statement such as ‘at’:

at >nul 2>nul
if errorlevel 1 echo you are not in administrator mode

Test if Network Directory exists in Batch file (.cmd)

February 16, 2012

The default way to check whether a directory exists in a Windows batch file (.cmd) is

if not exist "%directory%\nul" (
   echo %directory% does not exist
)

However, as this MS KB explains, the check for the NUL file does not work with directories on network drives mapped to a drive letter.

A working solution I found is to process the ERRORLEVEL value a DIR command sets

dir %directory% >nul 2>nul
if errorlevel 1 (
   echo %directory does not exist
)

or

dir %directory% >nul 2>nul
if not errorlevel 1 (
    echo %directory exists
)

Also note that mapped network drives are not available in administrator mode, as is discussed in these threads.


Analyzing Visual Studio Solutions

February 7, 2012

VS Solution Dependency Visualizer was originally started as a tool to generate dependency charts of projects and assemblies contained in a Visual Studio Solution (.sln) file.

As the program evolved, textual analysis features have been included: display lists of referencing and referenced projects and assemblies, list containing directories, etc.

The new version 0.70 of VS Solution Dependency Visualizer adds more analysis functions:

List Project Properties

displays Output Type, Assembly Name, Root Namespace, and Framework Version

List Namespaces


analyzes C# projects for namespace declarations

List Web URLs

extracts the URLs of Web Application projects

List Web Service URLs

extracts URLs of .asmx files and web service declarations from app.config.

Dependency Chart

The application’s user interface has been re-worked so that the dependency chart is now contained in a tab of the (single) main window.

Project Coupling

displays coupling metrics indicating stability and responsibility of included projects.

More screenshots can be viewed in the gallery. As usual, the latest release of VS Solution Dependency Viewer is available for download here.


Follow

Get every new post delivered to your Inbox.