Don’t forget add EntitySpaces operands to Where method.

In EntitySpaces  you can specify filter to load data. I’ve wrote the following code



EmployeesCollection collection = new EmployeesCollection();   
Collection.Query.LastName.Like(“A%”)   
collection.Query.Load();   


and couldn’t understand why the filter doesn’t work.


The reason is that functions similat to Like, LessThan return esWhereItem that will work only after they passed to esDynamicQuery.Where(Object[]()) method.
So the correct code must be


Dim collection As EmployeesCollection = New EmployeesCollection()  
collection.Query.Where(collection.Query.LastName.Like(“A%”))
collection.Query.Load()     

Exclude non-stringable columns in EntitySpaces templates.

In MyGeneration template for EntitySpaces (see Template: Ajax Auto Complete WebServices using EntitySpaces) I wanted to loop through all columns of the table but exclude those that can not be converted to string(e.g TimeStamp).
It’s can be done by calling EntitySpaces esPlugIn methods IsObjectType and IsArrayType

  foreach(IColumn col in cols)
  {
    if(!esPlugIn.IsArrayType(col) && !esPlugIn.IsObjectType(col))
    {//exclude fields like TimeStamps
         //put your code here
    }
  
  }

Possible reasons for Access messages “Data Being Updated by Another User”

I was asked to investigate, why in Access 2000 linked table(to SQL server database) any change in data was refused with message returning “Data Being Updated by Another User”.

The actual message could be misleading, because it returns if Update SQL returns 0 records back.
Access creates dynamic SQL passing in WHERE clause current values of fields.
However if column was created as BIT NULL and actually has NULL value, access sends in WHERE columnName=0 , which causes mismatch.
The problem happened in MS Access 2000 and MS Access XP.

Another issue in  Access 2000(not a problem in XP) is if your DateTime column stores seconds(or seconds with milliseconds). The access passes back in WHERE value in format ‘Dec 8 2006 5:59PM’ truncating seconds and milliseconds, which causes mismatch.

Possible  workarounds:
1. Run SQL
 update Table  set BitNullableColumn=0 where BitNullableColumn is null


update Table  set DateTimeColumn=Convert(nvarchar(30) ,DateTimeColumn, 0)


2. Create your BIT columns as NOT NULL.



3. Do not use old versions of Access( hope that new versions of Access handle the issue correctly)


4. Do not use  Access at all.


5. Update: I was adviced that the way to solve this problem is to add a timestamp field to each row. When you do this, Access uses an optimistic locking strategy and is able to recognise if you’re altering the same version of the record. Timestamps heve been supported since (at least) Access 95.

My notes about MyGeneration Templates

I’ve started to use MyGeneration  templates. They are very powerful and easy to customize. However I feel it is not always easy to find documentation.It is split between different sites and also not searchable by Google(see discussions here and here).So I decided to put  here the links that are useful for me .

The introductiontoMyGeneration can be found in articles on CodeProject and dotnet.sys-con.com.

MyGeneration allows to write scripts in VBScript,JScript, C# and VB.Net. In DotNetScript UI can be written using use the standard .Net windows forms and propriatory Zeus input form. I prefer to use C# DotNetScript with using WinForms -and the authors of EntitySpaces use the same in their ASP.NET templates. However many of the old templates in the Template Library are written using other languages, which makes it a little bit harder to copy and paste code snippets. 

There is set of articles in TemplateLibrary.
For me the most useful are Developing DotNetScript Templates – MyGeneration  and MyGeneration Project Files.
(don’t waste your time to open articles, authored by lmterra  – they currently refer to dead links).

In forums site there is Tips and Tricks forum with Include Files in MyGeneration, , Your First MyGeneration Plug-In and SubTemplate Execution  tips.

The procedure of debugging is described here and in the help  . However I found it is required some tricks to show source – see Debug in VS2005 thread.

To  create easier UI for templates see MyGeneration.zip in dOOdads ASP.NET Inline Grid archive and in particular comment at the end of the post from  my.generation :

I added the project that I used to create the UI to the archive. It’s called MyGeneration.zip. MyMeta wont run unless you call the application MyGeneration, thus the name. Anyway, notice the use of the variable “input” which is a hash table, when I copy this code in the UI I only copy the code from MyForm_Load() on down. It makes for an extremely fast way to write/debug full winform UI’s. Just change the connection string in the Main() function where it creates and initializes a MyMeta object.

See also discussion Creating the GUI part of the template in Visual Studio

Alternative approach to creating UI in searate DLL shown in archive:Embedding Windows Forms in the Template UI .
Not sure, does Syntax-colouring plug-in for MyGeneration UI add any value,or current implementation sufficient.

Environment variables for template from Zeus API Reference Zeus.ZeusInput . The current template script metadata are accessible through  IZeusTemplateStub class.The sample to get them (e.g. Template Title) is shown here

To output ASP.NET dynamic tags <% and %> from templates see post .

I’ve posted template: Ajax Auto Complete WebServices using EntitySpaces

“Configure Data Source” Wizard reads assemblies from BIN directory regardless of specified Build Output Path in VB WAP project

Today I wanted to add Object Data Source(located in another DLL) to User Control in VB WAP project.
“Configure Data Source”Wizard showed me  “Choose your Business Object” drop-down list with some objects from my DLL, but not the newest, that I’ve created recently. I’ve rebuild my projects a few times,cleaned solution,closed and re-opened Visua Studio -it didn’t help. My new data classes were not included in the combo-box. When I added class typemanually in the markup view, Wizard reported, that class couldn’t be found- maybe it is not in the BIN direcory.


I searched my hard drive for all versions of  my business objects DLL and deleted old files from all directories. There was a change-all classes from my DLL disappeared from the drop-down list. Finally I’ve noticed, that my WAP project has DLLs in BIN, BINDEBUG and BINRELEASE directories.


Some time ago I decided to set Build Output Path as binDEBUG and BINRELEASE for different configurations.
(I did it to use consistent batch file for VB and C# Library projects.Note that new library projects in VS 2005 are  created with separate targets for debug and release. But WAP VB project has one BIN as target for both configurations)
I haven’t cleaneed BIN folder itself and it had old versions of referenced DLLs. Now I deleted them from BIN folder and “Choose your Business Object” drop-down list became completely empty.

The conclusion:


VB WAP “Configure Data Source”Wizard reads assemblies from BIN directory regardless of specified Build Output Path.



I’ve raised MS Connect Bug report “Configure Data Source Wizard doesn’t find classes if Build Output Path is changed in VB WAP” .


A few lessons for myself:


1. Don’t modify Build Output Path for VB WAP project.
2. Don’t use VB if possible-(“Configure Data Source”Wizard in C# WAP is smart enough to search correct Build Output Path for available DLLs )


DotNetnuke 4.4 RewriterUtils.RewriteUrl breaking change in adding QueryString.

I am using modified version of DNN HttpModulesUrlRewriteUrlRewriteModule,
in particular I am calling their
Friend RewriterUtils.RewriteUrl function. In 4.0.3 version it expected URL parameter without QueryString and added queryString from context.Request.QueryString inside the function.
But in 4.4. my code stopped working.
The reason was that they removed the code to add querystring information from the function and made it  responsibility of a caller.
It certainly makes sense, but it will be easier for me(and other developers), if comments with description how function works and what the changes are done will be added to the source code.
It is the expected code style for open source project.


My FileHelper class

I’ve posted a few code snippets and some people noticed that there are references to unresolved methods.I am using a few helper classes. This post describes my FileHelper class:

System.IO;
     
/// <summary>
      /// Summary description for FileHelper.

using

    /// See also StreamHelper class methods, e.g. SaveStringToFile,SaveToFile

      /// </summary>

      public static class FileHelper

      {

            public static string GetFileExtensionWithoutDot(string fileName)

            {

                  string sExt=Path.GetExtension(fileName);

                  if ((null==sExt) | (sExt==string.Empty ))

                        return string.Empty;

                  return sExt.Remove(0,1);

            }

        //sourced from internal HtmlAgilityPack IOLibrary http://smourier.blogspot.com/2005/05/net-html-agility-pack-how-to-use.html

        public static void MakeWritable(string path)

        {

            if (!File.Exists(path))

                return;

            File.SetAttributes(path, File.GetAttributes(path) & ~FileAttributes.ReadOnly);

        }

        //sourced from internal HtmlAgilityPack IOLibrary http://smourier.blogspot.com/2005/05/net-html-agility-pack-how-to-use.html

        // if target directory doesn’t exist, create it

        // if target file is read-only, overwrite it

        //NOte: if source file is read-only, copied file will be also read-only

        public static void CopyAlways(string source, string target)

        {

            if (!File.Exists(source))

                return;

            Directory.CreateDirectory(Path.GetDirectoryName(target));

            MakeWritable(target);

            File.Copy(source, target, true);

        }

        //from http://www.codeproject.com/cs/files/copydirectoriesrecursive.asp

        // alternative use Win API or (http://www.bubble-media.com/cgi-bin/articles/archives/000026.html)

        // Copy directory structure recursively

        public static void CopyDirectory(string Src,string Dst)

        {

            String[] Files;

 

            if(Dst[Dst.Length-1]!=Path.DirectorySeparatorChar)

                Dst+=Path.DirectorySeparatorChar;

            if(!Directory.Exists(Dst)) Directory.CreateDirectory(Dst);

            Files=Directory.GetFileSystemEntries(Src);

            foreach(string Element in Files){

                // Sub directories

                if(Directory.Exists(Element))

                    CopyDirectory(Element,Dst+Path.GetFileName(Element));

                // Files in directory

                else

                    File.Copy(Element,Dst+Path.GetFileName(Element),true);

                }

        }

        //from http://www.pgacon.com/visualbasic.htm#Creating_a_temporary_file_name

        public static string MakeTempFileName(string path, string ext)

        {

            int x;

            string s;

            if (String.IsNullOrEmpty(ext))   ext = “.tmp”;

            //if (path == “”)

            //{

            //    path = App.path;

            //}

            //if ((Right(path, 1) != “\”))

            //{

            //    path = path + “\”;

            //}

            x = 0;

            do

            {

                x = x + 1;

                s = path + x + ext;

            } while (File.Exists(s));

            return s;

        }

        /// <summary>

        /// FileInfo and DirectoryInfo derived from ABSTRUCT class FileSystemInfo,

        /// so MS doesn’t provide standard method to open path without trying one or another class

        /// </summary>

        /// <param name=”fi”></param>

        /// <returns>can return null if path is not found</returns>

        public static FileSystemInfo GetFileOrDirectory(string path)

        {

            //alternatively call File.GetAttributes and the open either FileInfo or DirectoryInfo

            FileInfo fi = new FileInfo(path);

            if(fi.Exists)

            {

                return fi; 

            }

            else

            {

                DirectoryInfo di = new DirectoryInfo(path);

                if (di.Exists)

                {

                    return di;

                }

            }

            return null;

        }

 

        public static bool IsDirectory(FileSystemInfo fi)

        {

            bool bRet = (fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory;

             return bRet;

        }

        public static bool IsValidUNCDirectoryPath(string sPath)

        {//http://channel9.msdn.com/ShowPost.aspx?PostID=135681

            Uri uri;

            bool bRet = Uri.TryCreate(sPath, UriKind.Absolute, out uri) && uri.IsUnc;

            return bRet;

        }

        //from SessionToolsSESSIONSessionManagerStartEnd.vb

        public static string GetPathInTempFolder(string AppName,string InstanceName, string RelativeFileName)

        {

            if(RelativeFileName==null){   throw new ArgumentNullException(“RelativeFileName”);}

            string sTempFolderName = Path.GetTempPath();// ‘        Environment.GetEnvironmentVariable(“TEMP”)

            if (!String.IsNullOrEmpty(AppName))

            {

                sTempFolderName = Path.Combine(sTempFolderName, AppName);

            }

            if (!String.IsNullOrEmpty(InstanceName))

            {

                sTempFolderName = Path.Combine(sTempFolderName, InstanceName);

            }

            string pathTarget = Path.Combine(sTempFolderName, RelativeFileName);

            string sTargetDir = Path.GetDirectoryName(pathTarget);

            if ((!(Directory.Exists(sTargetDir))))

            {

                Directory.CreateDirectory(sTargetDir);

            }

            return pathTarget;

        }

        public static string RemoveInvalidFileNameChars(string FileName)

        {

            char[] chars = Path.GetInvalidFileNameChars();

            string[] parts = FileName.Split(chars);

            return String.Join(“”, parts);

        }