Les requêtes XPath permettent de faire du requetage sur un fichier XML afin de trouver facilement et rapidement un ou plusieurs noeuds XML.
En .net, on peut faire une requête XPath à partir d'un objet XmlNode via les méthodes SelectSingleNode ainsi que SelecNodes.
Par exemple si on a ce fichier XML :
<?xml version="1.0" encoding="utf-8" ?>
<Pouets>
<Pouet>Pouet N°1</Pouet>
</Pouets>
On peut obtenri le premier noeud Pouet ainsi :
XmlDocument doc = new XmlDocument();
doc.Load("pouet.xml");
Console.WriteLine(doc.SelectSingleNode("//Pouet") != null);
(Bien sur XPath est beaucoup plus puissant que ça, mais ce n'est pas l'objet du post.)
Malheureusement ça se gate si on travail avec des fichiers XML complexes : avec plusieurs namespaces XML. Par exemple si on a ce fichier :
<?xml version="1.0" encoding="utf-8" ?>
<Pouets xmlns="pouetNamespace">
<Pouet>Pouet N°1</Pouet>
</Pouets>
Le code plus haut ne fonctionne plus ! Après un tour dans la documentation, on peut utiliser un XmlNamespaceManager afin de résoudre les namespaces XML.
On pourrait alors écrire :
XmlDocument doc = new XmlDocument();
doc.Load("pouet.xml");
XmlNamespaceManager xmlnsmgr = new XmlNamespaceManager(doc.NameTable);
xmlnsmgr.AddNamespace(String.Empty, "pouetNamespace");
Console.WriteLine(doc.SelectSingleNode("//Pouet", xmlnsmgr) != null); // => doesn't work !
Mais cela ne fonctionne toujours pas. En lisant d'avantages la doc, il y a une partie sur les requêtes XPath et namespaces par défaut.
If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URI to the XmlNamespaceManager; otherwise, you will not get a node selected. For more information, see Select Nodes Using XPath Navigation.
Pour requêter un fichier XML ayant un namespace par défaut, on est donc obligé de rajouter un namespace avec un prefixe, ce qui donne :
XmlDocument doc = new XmlDocument();
doc.Load("pouet.xml");
XmlNamespaceManager xmlnsmgr = new XmlNamespaceManager(doc.NameTable);
xmlnsmgr.AddNamespace("dummy", "pouetNamespace");
Console.WriteLine(doc.SelectSingleNode("//dummy:Pouet", xmlnsmgr) != null);
Je trouve ce comportement étonnant et absolument pas intuitif. De plus, l'impossibilité de récupérer un XmlNamespaceManager à partir d'un XmlDocument rend l'utilisation de XPath via .net sur des fichiers XML complexe très pénible. Je ne parle même pas de l'utilisation de XPath via XLinq (Linq to XML), qui est complètement impossible sauf en passant par un XmlReader ou le contenu littéral du XML.
Lorsque l'on développe des sites internet, on aimerait bien savoir ce que contient le cache de notre navigateur, certes on peut utiliser des analyseurs de trames HTTP comme firebug, fiddler, httpwatch, mais ce n'est pas ce qu'il y a de plus pratique.
J'ai récemment découvert une astuce pour Firefox. Dans l'url il suffit de taper "about:cache", vous aurez alors la possibilité de lister le contenu du cache disque et mémoire de votre Firefox :
"about:cache"
"about:cache?device=memory"
"about:cache-entry"

A noter que l'on peut utiliser, l'extension CacheViewer qui permet d'obtenir les différents éléments du cache d'une façon plus graphique.
Quel outil pour Internet Explorer ?
A partir de là, je me suis dit qu'il serait intéressant d'avoir une astuce similaire pour Internet Explorer. Malheureusement je n'ai rien trouvé de très pratique, la seule piste est une appli (avec les sources en C++) qui utilise l'API WinInet pour accéder au cache "Reading the Internet Explorer Cache"
Petite chose amusante essayer d'accéder à "about:robots" dans votre Firefox 3 ;-)
Lorsqu'on utilise un service WCF, il se peut que l'on ne possède pas le contrôle des différents types que l'on transfère. Dans ce cas il est possible d'avoir des problèmes pour sérialiser, en effet, ne pouvant pas modifier le type, on ne peut pas rajouter des attributs utiles à la sérialisation, rajouter un constructeur vide, ...
Ces problèmes surviennent quelques soit le binding utilisé, dans la suite de mon exemple j'utilise le netTcpBinding.
J'ai récemment été confronté à ce problème, après pas mal de recherche, j'ai trouvé une solution qui me convenait, celle-ci ne nécessite pas de réécrire une version simplifié de l'objet à transiter.
Pour cela j'ai créé une classe possédant une propriété du type de l'objet à transférer. Dans mon exemple, l'objet qui pose problème lors de la sérialisation est de type Query.
public class QueryEncapsulator{
public QueryEncapsulator()
{ }
public QueryEncapsulator(Query q)
{
this.Query = q;
}
public Query Query { get; set; }
}
Bien sur, cela ne suffit pas pour résoudre le problème, l'étape suivante est d'implémenter l'interface IXmlSerializable. Cette interface va nous permettre de personnaliser la sérialisation de cet objet, pour ne pas avoir de problème nous allons utiliser une sérialisation binaire via le BinaryFormatter puis écrire le binaire dans le XMLWriter en base64.
[Serializable]
public class QueryEncapsulator : IXmlSerializable
{
public QueryEncapsulator()
{ }
public QueryEncapsulator(Query q)
{
this.Query = q;
}
public Query Query { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
BinaryFormatter formatter = new BinaryFormatter();
Byte[] b = new Byte[1024];
using (MemoryStream ms = new MemoryStream())
{
if (!reader.Read())
throw new Exception("boom");
int i;
while ((i = reader.ReadContentAsBase64(b, 0, b.Length)) > 0)
{
ms.Write(b, 0, i);
}
ms.Position = 0;
Query obj = (Query)formatter.Deserialize(ms);
this.Query = obj;
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, this.Query);
Byte[] b = ms.ToArray();
writer.WriteBase64(b, 0, b.Length);
}
}
}
A partir de là, nous pouvons transférer notre objet QueryEncapsulator à la place de notre objet Query.
Mais pourquoi cette astuce fonctionne ? En effet, pourquoi une sérialisation binaire via le BinaryFormatter fonctionne alors que lorsqu'on utilise le NetTcpBinding le message est transféré sous forme binaire.
[disclaimer:information non confirmé] D'après ce que j'ai compris, quelque soit le binding utilisé la sérialisation WCF se fait via le DataContractSerializer. Ce DataContractSerializer utilise en interne les mécanismes sous-jacent de la sérialisation XML afin de créer le graph de la sérialisation. Cela implique que l'on peut utiliser l'interface IXmlSerializable afin de personaliser la sérialisation.
Niveau performance, le surcout de cette astuce est négligeable par rapport à la machinerie WCF, dans mon cas, le surcout ne prend pas 1ms alors que le service met entre 5 et 30ms à répondre.
Lorsque vous développer des grosses applications avec Visual Studio, il est parfois nécessaire de démarrer plusieurs projets en même temps pour pouvoir tester son code. C'est typiquement le cas avec WCF, on a souvent besoin de lancer l'application hébérgeant le service WCF ainsi que l'application consommant ce service.
Dans Visual Studio, il est possible de configurer au niveau de la solution plusieurs projets de démarrage. Pour cela allé dans les propriétés de la solution (clique droit sur la solution puis propriétés), il y a une page "Startup Project" qui permet de définir le ou les projets de démarrage.

Lorsque vous créez un service WCF, vous allez créer un contrat. Dans la plupart des cas, ce contrat est une interface décorée de l'attribut ServiceContract contenant des méthodes décorées de l'attribut OperationContract.
Si vous voulez retourner un objet d'un type enfant du type déclaré vous obtiendrez une exception de type : "CommunicationException".
Prenons cet exemple :
[ServiceContract]
public interface IMyService
{
[OperationContract]
Animal GetAnimal(String name);
}
[DataContract]
public abstract class Animal
{ }
[DataContract]
public class Dog : Animal { }
[DataContract]
public class Cat : Animal { }
L'implémentation de ce contrat retournera soit un objet de type Dog ou un objet de type Cat suivant la valeur du paramètre name.
Lors de l'utilisation de ce service vous obtiendrez une CommunicationException :
There was an error while trying to serialize parameter http://tempuri.org/:query. The InnerException message was 'Type 'Test.Dog' with data contract name 'Dog:http://schemas.datacontract.org/2004/07/Test.Doc' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
La raison est que vous retournez un objet qui n'est pas connu du service, il ne sait alors pas comment le sérialiser. Pour palier à ce problème, il faut faire connaitre ces types à notre service. Il existe plusieurs solutions :
- Utilisation de l'attribut ServiceKnownType : Cet attribut s'utilise au niveau du contrat soit sur la définition de l'interface, soit sur les différentes méthodes de l'interface :
[ServiceContract]
public interface IMyService
{
[OperationContract]
[ServiceKnownType(typeof(Dog))]
[ServiceKnownType(typeof(Cat))]
Animal GetAnimal(String name);
}
- Utilisation de l'attribut KnownType : Cet attribut s'utilise au niveau de la classe mère :
[DataContract]
[KnownType(typeof(Dog))]
[KnownType(typeof(Cat))]
public abstract class Animal
{ }
<configuration>
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Test.Animal, MyAssembly">
<knownType type="Test.Dog, MyAssembly"/>
</add>
<add type="Test.Animal, MyAssembly">
<knownType type="Test.Dog, MyAssembly"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
</configuration>
Il existe d'autres solutions, mais toutes dérives de ces 3 solutions. J'aime particulièrement la solution qui consiste à appeler une méthode static d'un certain type, cette solution permet d'inclure des KnownType générique ou alors d'inclure tous les enfants d'un type via de la reflection.
Pour en savoir plus sur comment référencer vos types dans le contrat, je vous conseille cet article : All about knownTypes ou cet article MSDN : Data Contract Known Types
Lorsqu'on créé une section de configuration personnalisé, .net permet de valider les entrées grâce aux attributs StringValidator et RegexStringValidator.
J'ai voulu utiliser l'attribut RegexStringValidator sur un élément de ma configuration afin de vérifier que l'entrée contenait un String "simple", j'ai donc écrit ce code :
public class IndexElement : ConfigurationElement
{
[RegexStringValidator(@"[\w\-\.]+")]
[ConfigurationProperty("Name", IsKey = true, IsRequired = true)]
public String Name
{
get { return (String)base["Name"]; }
set { base["Name"] = value; }
}
}
Dans mon fichier de configuration, j'ai rajouté la ligne qui va bien, mais lorsque je charge la configuration j'obtiens cette erreur :
The value for the property 'Name' is not valid. The error is: The value does not conform to the validation regex string '[\w\-\.]+'.
Après quelques recherches, je me suis rendu compte que .net valide également la valeur par défaut, dans mon cas cette valeur vaut null ce qui ne valide pas l'expression régulière.
Pour corriger le problème, il faut renseigner une valeur par défaut, on peut le faire via l'attribut ConfigurationProperty.
[RegexStringValidator(@"[\w\-\.]+")]
[ConfigurationProperty("Name", IsKey = true, IsRequired = true, DefaultValue="abc")]
public String Name
{
get { return (String)base["Name"]; }
set { base["Name"] = value; }
}
La valeur par défaut importe peu, en effet si on ne renseigne pas la propriété, .net va retourner une exception puique nous avons marquer cette propriété comme "Required".
Toutes les personnes ayant déjà utilisé WCF savent à quel point il est pénible de faire la configuration. En effet WCF repose essentiellement sur des fichiers de config qui possèdent de très nombreuses options, éditer ce fichier de config à la main devient vite un enfer.
Lorsque vous créez un nouveau projet de type "WCF Service Library" :
Vous pouvez modifier le fichier de config du projet via un éditeur spécial :
Malheureusement lorsque l'on fait un client, ou alors qu'on décide d'héberger "manuellement" notre service WCF, on ne dispose pas de cette option.
Pour palier à ce manque, on peut rajouter notre propre éditeur à n'importe quel fichier. Pour cela faites un click droit sur le fichier de config dans l'explorateur de solution puis "Ouvrir Avec ...", il faut ensuite rajouter un nouvel éditeur. svcConfigEditor se trouve ici : "C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin\SVCConfigEditor.exe"
SVCConfigEditor nous permet de configurer toute les options de WCF. Si vous ne le connaissez pas et utilisez WCF, je vous invite grandement à le découvrir, attention cet outil nécessite malgré tout de comprendre le fonctionnement de la configuration WCF.

Grâce au service web et ASP.net Ajax, il est très simple de communiquer avec notre serveur à partir de JavaScript. En effet, il suffit de créer un service WCF (ou asmx) de rajouter quelques attributs et on peut appeler nos WebMethods à partir de JavaScript. En interne une sérialisation JSON (JavaScript Object Notation) est utilisée.
Malheureusement il est impossible de customiser cette sérialisation. Pourquoi vouloir personnaliser cette sérialisation ? Prenons le cas d'une méthode GetPersons qui renvoie une centaine de personne.
Le JSON aura cette tête :
{"d": [
{
"__type":"Person:#",
"BirthDate":"\/Date(1211790363564+0200)\/",
"City":"Chénas",
"FirstName":"Steven",
"LastName":"Vincent"
},{
"__type":"Person:#",
"BirthDate":"\/Date(1211790441107+0200)\/",
"City":"Légny",
"FirstName":"Janet",
"LastName":"laurent"
},{
// etc...
On peut voir que le nom des "colonnes" se répètent inutilement. L'idée serait d'avoir un JSON ayant cette tête :
{"d":{
"Columns":[
"FirstName",
"LastName",
"BirthDate",
"City"
],"Values":[
["Andrew","Alex","\/Date(1211790586937+0200)\/","Saint-Didier-sur-Beaujeu"],
["Laura","Claude","\/Date(1211790697591+0200)\/","Chénas"],
["Anne","Isabelle","\/Date(1211790655756+0200)\/","Saint-Cyr-le-Chatoux"],
["Nancy","Steph","\/Date(1211790592372+0200)\/","Sainte-Paule"],
// etc
Pour arriver à un tél résultat, je ne retourne plus une List<Person> mais une JsonList<Person>. Cette JsonList<T> possède 2 propriétés : Columns de type IEnumerable<String> et Values de type IEnumerable<IEnumerable<Object>>.
Dans mon exemple, pour 100 personnes, on passe de 12.8 ko à 6.8 ko, soit presque 50%. Cette optimisation nous permet alors d'obtenir une application plus réactive.
Côté client, pour retrouver un tableau d'objet plutôt qu'un objet "bizarre", on pourra utiliser ce code :
// permet de retourner un tableau d'objet classique plutot qu'une objet bizarre
var a = [];
var propCount = result.Columns.length;
var propNames = result.Columns;
for(var i = 0, l = result.Values.length; i < l; i++){
var values = result.Values[ i ];
var o = {};
for(var j = 0; j < propCount; j++){
o[propNames[j]] = values[j]
}
a[a.length] = o;
}
Le code et l'exemple de cette JsonList se trouve sur aspfr : Optimisation de la sérialisation Json pour les List<T>
Mais où est donc passé le framework 3.5 dans IIS ? En effet si l'on regarde dans IIS on voit qu'on peut choisir la version de ASP.net.
Sous IIS6 (Win 2003) :

Sous IIS7 (Vista) :

On voit sur les captures que l'on peut choisir entre le framework 1.1 et 2.0 mais pas de framework 3.0 ni de 3.5, pourtant le framework 3.5 est bien installé.
C'est tout à fait normal ! Votre site .net 3.5 tournera très bien avec le framework .net 2.0, il n'y a rien à modifier.
Pour comprendre en quoi c'est normal, il faut d'abord se rappeler ce qu'est le framework 3.0 et 3.5 ; redo nous l'explique ici : qu'est-ce que le framework 3.5. Pour résumer le framework 3.x ne fait qu'apporter de nouvelles assemblies (des dll) à .net 2.0 ainsi que de nouveaux compilos (C#3 et VB9), .net 3.x se repose sur la CLR 2.0.
Lorsque vous créez un site .net 3.5, vous ne faites qu'utiliser ces nouvelles assemblies. Ces assemblies sont installées dans le GAC (Global Assembly Cache) lors de l'installation du framework 3.5, IIS n'aura alors aucun mal à les retrouver.
D'un point de vue IIS, votre site web 3.5, reste un "site 2.0" ayant un web.config un peu spécial (mais parfaitement conforme 2.0). Ce web.config référencie les assemblies de .net 3.5 ainsi qu'un nouveau compilo. Si vous voulez comprendre les différents éléments du web.config d'un site .net 3.5, je ne peux que vous conseillez l'article de Scott Mitchell : Dissecting ASP.NET Version 3.5's Web.config File
Il faut voir la combobox de choix du framework au niveau de IIS comme un choix de la CLR, et non comme le choix du framework !
Dans le cadre d'un test, j'ai récemment fait un service WCF qui ressemblait à peu près à ça :
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service
{
[DataContract]
public class Person
{
[DataMember]
public String FirstName { get; set; }
}
[OperationContract]
[WebGet]
public Person GetPerson()
{
return null;
}
}
J'ai donc rajouté une référence vers ce service au niveau de ma page pour que je puise accéder à ce service WCF en JavaScript.
<asp:ScriptManager runat="server">
<Services>
<asp:ServiceReference Path="~/Service.svc" />
</Services>
</asp:ScriptManager>
Lorsque l'on rajoute une référence vers un service WCF (ou asmx) via le ScriptManager. Lors de la phase de rendering, on ajoute un script vers /service.svc/js ce fichier contient le proxy nous permettant de dialoguer avec le WebService.
Dans le cas d'un nested type, le proxy généré contient ça :
var Service.Person=gtc("Service.Person:http://schemas.datacontract.org/2004/07/");
Ce qui fait évidemment planter le proxy puisque l'on ne peut pas déclarer une variable contenant le signe "."
Ce n'est pas très génant puisqu'on doit très rarement renvoyer des nested type (et je ne trouve pas ça propre). Je viens néanmoins d'ouvrir un bug sur connect : nested type in WCF with JSON Serialization
Visual Studio 2008 permet de créer des projets pour le framework 2.0, 3.0 et 3.5
.net 3.x n'étant que l'addition de quelques nouvelles assemblies, le choix d'utiliser tel ou tel framework au niveau de Visual Studio ne fait que restreindre les assemblies disponible lorsqu'on veut ajouter une référence.
Lorsqu'on a un projet de type C#, on peut facilement mettre à niveau le framework utilisé dans les propriétés du projet :
Par contre en VB, pas moyen de trouver cette option :

La seule solution que j'ai trouvée est de modifier le .vbproj en rajoutant la clé TargetFrameworkVersion
<Project ... >
<PropertyGroup>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
[Update]
Suite au commentaire de actionthomas, l'option se trouve dans l'onglet "Compile" puis "Advanced Compile Options"

Beaucoup de personnes ne savent pas utiliser le maximum de Reflector, certains ne connaissent même pas cet excellent outil. Pour lutter contre cette ignorance, j'ai écrit il y a quelques temps un tutorial de présentation de cet outil : Reflector : un décompilateur .net
J'aimerais revenir avec un exemple concret d'utilisation de la fonction "Analyze".
Imaginons que vous avez réussi à obtenir un fichier qu'une application .net utilise (en analysant les accès disques via filemon par exemple). Malheureusement, ce fichier est chiffré, il ne vous est donc pas possible de voir le contenu de celui-ci. Comme vous êtes tenace et curieux, vous décider d'analyser l'application .net avec Reflector.
Il y a deux solutions :
- soit vous utilisez le plugin CodeSearch pour trouver la méthode qui écrit le fichier, puis vous analysez cette méthode,
- soit vous êtes plus astucieux et vous décidez de vous servir de la fonction "analyze" de reflector.
Qu'est-ce que la fonction "Analyze" de Reflector ? C'est une fonction qui permet de savoir qui utilise une méthode, une classe, voir même une assembly.
A partir de là, on peut trouver toutes les méthodes qui utilise une méthode particulière.
Dans notre cas, on tente notre chance avec une classe de chiffrement du framework .net : Rijndaël. On s'aperçoit vite que cette classe est utilisée par notre assembly obfusqué.

Malheureusement la méthode est obfusqué et Reflector ne parvient pas à convertir le code MSIL de cette méthode vers du C#, on pourrait lire le code MSIL mais avant on va essayer d'être plus astucieux. En effet nous savons que pour utiliser la classe RijndaelManaged il faut une clé et une "IV" qui sont des Byte[], or on voit dans notre classe qu'il y a deux champs de type Byte[], regardons alors dans le constructeur de cette classe afin de vérifier si ces bytes n'ont pas été initialisé.

Nous avons donc réussit à obtenir très facilement la clé de chiffrement du fichier.
Comment complexifier le travail du vilain pirate ?
- Essayez de pirater votre code et voyez comment complexifier cette tâche.
- Utilisez un obfuscateur qui chiffre les strings, cela complexifiera la tache du pirate ; la version pro de dotfuscator le fait
- N'inscrivez pas la clé en dur dans votre code. Si votre application s'utilise avec un serveur, envoyez la clé seulement lorsque celle-ci est nécessaire !
Je ne suis pas expert en sécurité .net et je n'ai jamais eu cette problématique, si vous connaissez d'autres façon de protéger votre code, merci de partager votre expérience dans les commentaires.
Attention, ce post explique comment vérifier si son application est facilement piratable, je ne peux en aucun cas être tenu responsable de vos agissements.
Je viens de découvrir la méthode ScriptManager.RegisterDataItem, cette méthode permet de transférer des données entre le serveur et le client lors d'un AsyncPostback. Pour ceux qui ne sont pas familier avec les asyncpostback, un asyncpostback reprend le mécanisme d'un postback classique sauf qu'il se fait via Ajax (XMLHttpRequest) et ne rafraichit que certaines parties de la page, ces zones sont définies via les UpdatePanels.
En plus d'envoyer le contenu HTML des UpdatePanels à rafraichir, la méthode RegisterDataItem permet de transférer les données que l'on souhaite. Cette méthode dispose de deux signatures, soit l'on envoie un simple string, soit on envoie un objet complexe sérialiser en JSON.
// permet de renvoyer un simple string associé au ClientID d'un contrôle
ScriptManager1.RegisterDataItem(Label1, DateTime.Now.ToString());
// permet d'envoyer des données au format JSON
JavaScriptSerializer serializer = new JavaScriptSerializer();
Person p = new Person("Cyril", "Durand");
ScriptManager1.RegisterDataItem(Label2, serializer.Serialize(p), true);
Pour récupérer les données côtés clients, il faut s'abonner à l'événement pageLoading du pageRequestManager :
Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(function(sender, args){
var dataItems = args.get_dataItems();
var serverDate = dataItems['ClientID_Label1'];
var person = dataItems['clientID_Label2'];
});
Je trouve néanmoins dommage que la clé soit un objet de type Control et non un simple String, en effet, cela nécessite de connaitre le clientID du contrôle ce qui n'est pas toujours facile.
En C# il n'est pas possible d'avoir deux méthodes ayant une signature identique qui différent seulement par le type de retour.
public class Foo
{
public int Bar()
{
return 0;
}
public String Bar()
{
return "pouet";
}
}
En MSIL c'est possible. Le code ci dessous compile parfaitement.
.assembly Foo{}
.module Foo.dll
.class public CFoo
{
.method public static int32 Bar()
{
ldc.i4.0
ret
}
.method public static string Bar()
{
ldstr "Toto"
ret
}
}
Lorsqu'on fait un appel de méthode en MSIL, on spécifie le nom complet de la méthode :
call int32 CFoo::Bar()
// ou
call string CFoo::Bar()
Que se passe t'il en C# ? Comment spécifier la méthode que l'on veut utiliser ?
L'IntelliSense de Visual Studio nous propose la méthode Bar qui retourne un String, mais si nous utilisons cette méthode.
Nous avons une erreur de la part de compilation :
J'ai essayé en castant la méthode (String)CFoo.Bar() mais même erreur. J'ai tenté VB, l'IntelliSense ne me propose même pas de méthode Bar.
Quelle est alors l'utilité de ce type de surcharge ? J'en ai trouvé qu'une seule, cela permet aux obfuscateurs de complexifier le code. En effet, si notre classe possède des méthodes GetPerson() et GetCompany() qui retournent respectivement une List<Person> et une List<Company>, un obfuscateur pourra utiliser le même nom pour renommer ces méthodes.
Est-ce que C# doit pouvoir utiliser/créer de tels surcharges ?
Techniquement, l'inférence de type nous permettrait de ne pas avoir trop d'ambigüité, si cela ne suffit pas on pourra toujours caster explicitement, afin de séléctionner la bonne méthode.
Conceptuellement, bien que dans certains cas cela puisse être utile, je ne pense pas que cela soit une bonne chose, cela risque de complexifier le code pour peu. L'utilisation des generics, nous permet dans la majorité des cas d'obtenir des solutions alternatives.
Et vous qu'en pensez vous ? Est-ce que le futur compilateur devra prendre ce cas en compte ?
Lorsque l'on fait une requête vers un service WCF / ASMX "Ajax enabled" il se peut que l'on ait besoin de passer des paramètres qui ne sont pas propres à la méthode, par exemple un ticket d'authentification, ...
Ajout d'un paramètre dans le header de la requête (donc coté client) :
Pour ajouter un paramètre dans le header HTTP de la requête il faut s'abonner à l'événement invokingRequest.
Sys.Net.WebRequestManager.add_invokingRequest(function(){
e._webRequest._headers['CacheID'] = ...
});
Côté serveur on peut relire le paramètre via :
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public List<Person> GetPersons(