Blog du Pôle .NET

Partager pour mieux développer...

Lorsque le Guid ne convient pas, le ShortGuid arrive à la rescousse

clock April 30, 2009 11:02 by author gcelet

Il arrive, dans certains scénario, que le Guid n'est pas adapté: il est trop long ou il n'est pas très joli! Mais lorsque l'on a gouté au Guid, il est difficile de s'en passer. Il existe un moyen de raccourcir un Guid: le ShortGuid!

Le ShortGuid s'utilise exactement de la même façon que le Guid:

ShortGuid shortGuidEmpty = ShortGuid.Empty; // Crée un ShortGuid vide
ShortGuid shortGuidA = ShortGuid.NewGuid(); // Crée un nouveau ShortGuid
Console.WriteLine("guidEmpty     : {0}", guidEmpty);
Console.WriteLine("shortGuidEmpty: {0}", shortGuidEmpty);
Console.WriteLine("shortGuidA    : {0}", shortGuidA);

Ce qui donne:

guidEmpty : 00000000-0000-0000-0000-000000000000
shortGuidEmpty: AAAAAAAAAAAAAAAAAAAAAA
shortGuidA    : 058fO04LSECNqoho_He67g

On peut convertir facilement le ShortGuid vers un Guid ou string:

Guid guidA = shortGuidA; // Convertit implicitement le ShortGuid en Guid
string stringA = shortGuidA; // Convertit implicitement le ShortGuid en String
Console.WriteLine("guidA         : {0}", guidA);

Ce qui donne:

guidA : 3b1f9fd3-0b4e-4048-8daa-8868fc77baee

Et inversement:

Guid guidB = Guid.NewGuid();
ShortGuid shortGuidB = guidB; // Convertit implicitement un Guid en ShortGuid
string stringC = "5Cqn2204Q0GTbI9dStW0fg";
ShortGuid shortGuidC = stringC; // Convertit implicitement une String en ShortGuid
Console.WriteLine("guidB         : {0}", guidB);

La comparaison avec le type Guid et String se fait naturellement:


Console.WriteLine("shortGuidA == shortGuidA: {0}", shortGuidA == shortGuidA);
Console.WriteLine("shortGuidA == shortGuidB: {0}", shortGuidA == shortGuidB);

Ce qui donne:

shortGuidA == guidEmpty: False
shortGuidA == shortGuidA: True
shortGuidA == shortGuidB: False

Voici le code de la classe ShortGuid:

/// <summary>
/// Represents a globally unique identifier (GUID) with a 
/// shorter string value. Sguid
/// </summary>
public struct ShortGuid : IComparable, IComparable<ShortGuid>, IComparable<Guid>, IComparable<string>
{
#region Static
/// <summary>
/// A read-only instance of the ShortGuid class whose value 
/// is guaranteed to be all zeroes. 
/// </summary>
public static readonly ShortGuid Empty = new ShortGuid(Guid.Empty);
#endregion
#region Fields
Guid _guid;
string _value;
#endregion
#region Contructors
/// <summary>
/// Creates a ShortGuid from a base64 encoded string
/// </summary>
/// <param name="value">The encoded guid as a 
/// base64 string</param>
public ShortGuid(string value)
{
_value = value;
_guid = Decode(value);
}
/// <summary>
/// Creates a ShortGuid from a Guid
/// </summary>
/// <param name="guid">The Guid to encode</param>
public ShortGuid(Guid guid)
{
_value = Encode(guid);
_guid = guid;
}
#endregion
#region Properties
/// <summary>
/// Gets/sets the underlying Guid
/// </summary>
public Guid Guid
{
get { return _guid; }
set
{
if (value != _guid)
{
_guid = value;
_value = Encode(value);
}
}
}
/// <summary>
/// Gets/sets the underlying base64 encoded string
/// </summary>
public string Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
_guid = Decode(value);
}
}
}
#endregion
#region ToString
/// <summary>
/// Returns the base64 encoded guid as a string
/// </summary>
/// <returns></returns>
public override string ToString()
{
return _value;
}
#endregion
#region Equals
/// <summary>
/// Returns a value indicating whether this instance and a 
/// specified Object represent the same type and value.
/// </summary>
/// <param name="obj">The object to compare</param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj is ShortGuid)
return _guid.Equals(((ShortGuid)obj)._guid);
if (obj is Guid)
return _guid.Equals((Guid)obj);
if (obj is string)
return _guid.Equals(((ShortGuid)obj)._guid);
return false;
}
#endregion
#region GetHashCode
/// <summary>
/// Returns the HashCode for underlying Guid.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return _guid.GetHashCode();
}
#endregion
#region NewGuid
/// <summary>
/// Initialises a new instance of the ShortGuid class
/// </summary>
/// <returns></returns>
public static ShortGuid NewGuid()
{
return new ShortGuid(Guid.NewGuid());
}
#endregion
#region Encode
/// <summary>
/// Creates a new instance of a Guid using the string value, 
/// then returns the base64 encoded version of the Guid.
/// </summary>
/// <param name="value">An actual Guid string (i.e. not a ShortGuid)</param>
/// <returns></returns>
public static string Encode(string value)
{
Guid guid = new Guid(value);
return Encode(guid);
}
/// <summary>
/// Encodes the given Guid as a base64 string that is 22 
/// characters long.
/// </summary>
/// <param name="guid">The Guid to encode</param>
/// <returns></returns>
public static string Encode(Guid guid)
{
string encoded = Convert.ToBase64String(guid.ToByteArray());
encoded = encoded
.Replace("/", "_")
.Replace("+", "-");
return encoded.Substring(0, 22);
}
#endregion
#region Decode
/// <summary>
/// Decodes the given base64 string
/// </summary>
/// <param name="value">The base64 encoded string of a Guid</param>
/// <returns>A new Guid</returns>
public static Guid Decode(string value)
{
value = value
.Replace("_", "/")
.Replace("-", "+");
byte[] buffer = Convert.FromBase64String(value + "==");
return new Guid(buffer);
}
#endregion
#region Operators
/// <summary>
/// Determines if both ShortGuids have the same underlying 
/// Guid value.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static bool operator ==(ShortGuid x, ShortGuid y)
{
if ((object)x == null) return (object)y == null;
return x._guid == y._guid;
}
/// <summary>
/// Determines if both ShortGuids do not have the 
/// same underlying Guid value.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static bool operator !=(ShortGuid x, ShortGuid y)
{
return !(x == y);
}
public static bool operator ==(ShortGuid x, Guid y)
{
if ((object)x == null) return (object)y == null;
return x._guid == y;
}
public static bool operator !=(ShortGuid x, Guid y)
{
return !(x == y);
}
public static bool operator ==(Guid x, ShortGuid y)
{
if ((object)x == null) return (object)y == null;
return x == y._guid;
}
public static bool operator !=(Guid x, ShortGuid y)
{
return !(x == y);
}
/// <summary>
/// Implicitly converts the ShortGuid to it's string equivilent
/// </summary>
/// <param name="shortGuid"></param>
/// <returns></returns>
public static implicit operator string(ShortGuid shortGuid)
{
return shortGuid._value;
}
/// <summary>
/// Implicitly converts the ShortGuid to it's Guid equivilent
/// </summary>
/// <param name="shortGuid"></param>
/// <returns></returns>
public static implicit operator Guid(ShortGuid shortGuid)
{
return shortGuid._guid;
}
/// <summary>
/// Implicitly converts the string to a ShortGuid
/// </summary>
/// <param name="shortGuid"></param>
/// <returns></returns>
public static implicit operator ShortGuid(string shortGuid)
{
return new ShortGuid(shortGuid);
}
/// <summary>
/// Implicitly converts the Guid to a ShortGuid 
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
public static implicit operator ShortGuid(Guid guid)
{
return new ShortGuid(guid);
}
#endregion
#region CompareTo
public int CompareTo(object other)
{
if (ReferenceEquals(other, null))
return 1;
if (other is ShortGuid)
return CompareTo((ShortGuid) other);
if (other is Guid)
return CompareTo((System.Guid) other);
if (other is string)
return CompareTo((string) other);
throw new ArgumentException("other");
}
public int CompareTo(ShortGuid other)
{
return _guid.CompareTo(other._guid);
}
public int CompareTo(Guid other)
{
return _guid.CompareTo(other);
}
public int CompareTo(string other)
{
return _value.CompareTo(other);
}
#endregion
}

Grégory Célet

ShortGuid.cs (8.73 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Création de cube local avec C# et XMLA

clock April 14, 2009 11:13 by author aequoy

Le décisionnel est un de mes domaines fonctionnels d'origine, il m'arrive de temps à autre de répondre à des questions clients sur cette problématique.

Un client m'a donc récemment posé une colle. Comment faire pour qu'une application puisse créer puis attaquer un cube local programmatiquement via MDX sans passer par la case serveur d'analyse (Analysis Services en l'occurence) ?

Pour ce faire, je me suis tourné du côté de XML for Analysis (XMLA) afin de définir le schéma de mon cube. XMLA est une norme respectée par MS Analysis Services, Hyperion, SAP et SAS (autrement dit c'est un standard de fait sur le marché). Pour celles et ceux intéressés par la norme voyez du côté de ce lien.XMLA sert essentiellement de protocole de dialogue entre un serveur d'analyse et des applications tierces en s'appuyant sur SOAP. Une chose intéressante avec XMLA est qu'en plus d'être un protocole permettant l'interrogation de cubes analytiques, il permet aussi la création de ceux-ci.

Le schéma XMLA sera donc interprété via ADOMD.Net dans sa partie cliente (téléchargeable sur le site Microsoft). Une fois le cube local (*.cub) généré par ADOMD.Net je l'attaque classiquement.

Pour le bien de la démonstration, j'utilise la base Adventure Works afin d'aller chercher mes données mais toute source de données disposant d'une chaîne de connexion fera l'affaire.

1er problème : comment créer mon script XMLA ?

  • 1ère solution : je me tape la grammaire XMLA et je crée tout à la main. Cette solution est sympathique mais prend énormément de temps.
  • 2ème solution : j'utilise mon serveur d'analyse propiétaire et j'extraie un script XML. Loin de moi la fainéantise, mais j'ai privilégié cette approche.

Je vous conseille de récupérer une version gratuite SQL Server Express Advanced disposant des fonctionnalités d'analyse ainsi que les outils Visual Studio For Business Intelligence.

Je crée donc d'abord un projet d'analyse sous Visual Studio avec une source de données ici sur ma base relationnelle Adventure Works.  


 

 

 

 

 

 

 

 

Ma DataSourceView est assez simple :

 

  J'ai donc une table de fait Customer qui va disposer d'une seule mesure (Le nombre de client) exposée selon 2 dimensions : les territoires de vente et les magasins. Un schéma très simple pour l'exercice.

 Une fois publié, je sélectionne ma base de données sous management studio (à télécharger) après m'y être connecté et j'exporte le script XMLA. Bien faire attention d'exporter la base et non le cube !


J'obtiens un script que je sauvegarde sous mon répertoire c:\textcube.txt.

 2ème problème : comment créer la requête qui va manipuler le script pour générer le cube local ?

Le script de création seul ne suffit pas. Il faut l'englober dans un stub qui va se connecter à la source de données. Voici ce script gratuitement :) :

<Batch xmlns='http://schemas.microsoft.com/analysisservices/2003/engine'> 
CUBESCRIPT
<Parallel>  
<Process xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>    
<Object>      
<DatabaseID>Analysis Services Project1</DatabaseID>    
</Object>    
<Type>ProcessFull</Type>    
<WriteBackTableCreation>UseExisting</WriteBackTableCreation>  
</Process>
</Parallel>
</Batch> 

  A la place de CUBESCRIPT, je vais remplacer programmatiquement le schéma créé précédemment.Le stub est sauvegardé dans un autre fichier texte xmlastub.txt.

Notez bien que le DatabaseID doit être identique à celui présent dans le fichier textcube.txt.

S'en suit un programme C# qui va construire la requête :

 
AdomdConnection conn = new AdomdConnection();	
conn.ConnectionString = string.Format("Provider=MSOLAP;Data Source={0}", "c:\\cubedemo.cub"); 
try { 
conn.Open(); 
AdomdCommand cmd = new AdomdCommand(); 
cmd.Connection = conn;                       
string xmlastub = File.OpenText("C:\\xmlastub.txt").ReadToEnd();                    
string xmlacube = File.OpenText("C:\\TestCube.txt").ReadToEnd();                
cmd.CommandText = xmlastub.Replace("CUBESCRIPT", xmlacube);                     
cmd.Execute(); 
Console.WriteLine("ok"); }
catch (Exception ex) { Console.WriteLine(ex.Message); }
finally { conn.Dispose(); } Console.ReadLine(); 

 

Le cube est maintenant généré, il n'y a plus qu'à l'attaquer.

Une petite requête MDX pour la route :

AdomdConnection conn = new AdomdConnection();
            conn.ConnectionString = string.Format("Provider=MSOLAP;Data Source={0}", "c:\\cubedemo.cub");
            try
            {
                conn.Open();
                AdomdCommand cmd = new AdomdCommand();
                cmd.Connection = conn;
                cmd.CommandText = "select {[Measures].[Customer Count]} on columns, {[Store].[Business Entity ID].[Business Entity ID].Members} on rows from [MonTest]";
                AdomdDataReader monReader = cmd.ExecuteReader();
                while (monReader.Read())
                {
                    //lecture
                }
                Console.WriteLine("ok");
            }
            catch (Exception ex) { Console.WriteLine(ex.Message); }
            finally { conn.Dispose(); } Console.ReadLine();

Voilà !

Alexandre Equoy

PS : Si vous souhaitez changer la chaîne de connexion de la source, vous trouverez dans le fichier XMLA les lignes suivantes :

  <DataSources>
                <DataSource xsi:type="RelationalDataSource">
                    <ID>AdventureWorks</ID>
                    <Name>AdventureWorks</Name>
                    <ConnectionString>Provider=SQLNCLI10.1;Data Source=WVFROLDU01\SQL2008_ENT;Integrated Security=SSPI;Initial Catalog=AdventureWorks</ConnectionString>
                    <ImpersonationInfo>
                        <ImpersonationMode>ImpersonateServiceAccount</ImpersonationMode>
                    </ImpersonationInfo>
                    <Timeout>PT0S</Timeout>
                </DataSource>
            </DataSources>

Sachez aussi qu'Excel est capable d'ouvrir un fichier *.cub directement ce qui permet d'accéder aux fonctionnalités décisonnelles dans Excel sur ce cube local.

TestCube.rar (34,13 kb)

Currently rated 4.5 by 4 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Textarea avec Google Chrome

clock April 9, 2009 09:50 by author julien

Pour les adeptes de Google Chrome, vous avez surement remarqué que la Textarea (Textbox en mode MultiLine) est redimensionnable lors de l'exécution de votre page Web.
Certains vous diront que cela est très pratique surtout si celle-ci est de petite taille. Or, pour le développeur cela est peut-être inutile ou même embêtant car ca "casse" le montage.

La solution à ce problème est la suivante :
·          Dans le style de votre texarea ou TextBox (mode MultiLine), il vous suffit de rajouter l'expression !important lors de la définition de la largeur et/ou hauteur.

     Exemple :
                .CssTextArea { height: 100px !important; width: 200px !important; } 


Voilà voilà votre textarea n'est plus redimensionnable et prête à être publié.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Lenteur firefox sous Vista / Seven

clock April 8, 2009 10:46 by author Xavier Masclet
Certains auront remarqué que firefox est particulièrement long quand on dev en local sur un poste qui tourne sous Vista ou Seven.
L'astuce est la suivante, et m'a fait gagné 14 secondes sur le temps de chargement d'une page :

- Dans Firefox ouvrez un nouvel onglet
- Dans la barre d'adresse tapez : about:config
- Cliquez sur le bouton "I'll be careful, I promise"
- dans le filtre saisissez : ipv6
- double cliquez sur la ligne network.dns.disableipv6 pour mettre la valeur à 'true'.
- Redémarrez firefox

Voila c'est fait. Maintenant ca devrait aller beaucoup plus vite.
Cette astuce n'est valable que lorsqu'on fait tourner un site en local.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Calendrier

<<  July 2010  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678
Afficher en pleine page

Visiteurs