Dec 1, 2008
[ThreadStatic] and ThreadPool threads
Please note that using the CLR ThreadPool may re-use a thread and the state is still sticking to that thread.
May 18, 2008
Creating a WSDL using C#
Version one I found out was
ContractDescription cd = ContractDescription.GetContract(typeof(IContract));
System.ServiceModel.Description.WsdlExporter wexp = new System.ServiceModel.Description.WsdlExporter();
wexp.ExportContract(cd);
MetadataSet mds = wexp.GetGeneratedMetadata();
mds.WriteTo(new XmlTextWriter(@".\IContract.wsdl", Encoding.UTF8));
for a simple contract like
namespace WsdlExporter
{
[MessageContract]
public class RequestMessage
{
public Guid ID;
}
[MessageContract]
public class ResponseMessage
{
public string Name;
}
[ServiceContract(Namespace="http://www.mleder.blogspot.com/WsdlExporter/2008/04")]
public interface IContract
{
[OperationContract]
void Op1(string s);
[OperationContract]
int Op2();
[OperationContract]
ResponseMessage Op3(RequestMessage req);
}
}
I think this is verbose.
So I figured out version two, where I start with an "empty" WSDL file:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tns="http://localhost/remote"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
targetNamespace="http://localhost/remote"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://localhost/remote">
</s:schema>
</wsdl:types>
<wsdl:portType name="RemoteAddServiceSoap12">
</wsdl:portType>
<wsdl:binding name="RemoteAddServiceSoap12" type="tns:RemoteAddServiceSoap12">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
</wsdl:binding>
<wsdl:service name="RemoteAddService">
<wsdl:port name="RemoteAddServiceSoap12" binding="tns:RemoteAddServiceSoap12">
<soap12:address location="http://localhost:8765/RemoteAddService.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
and write some C# code:
// load an "empty" WSDL file (no types, messages, operations, ...)
// to start from and add operations by code
ServiceDescription wsdl = ServiceDescription.Read("empty.wsdl");
// add operation binding
OperationBinding myOperationBinding = new OperationBinding();
myOperationBinding.Name = "Add";
Soap12OperationBinding myOperation = new Soap12OperationBinding();
myOperation.Style = SoapBindingStyle.Document;
myOperation.SoapAction = "http://localhost/remote/Add";
myOperationBinding.Extensions.Add(myOperation);
// add input binding
InputBinding myInput = new InputBinding();
Soap12BodyBinding soap12BodyInputBinding = new Soap12BodyBinding();
soap12BodyInputBinding.Use = SoapBindingUse.Literal;
myInput.Extensions.Add(soap12BodyInputBinding);
myOperationBinding.Input = myInput;
// add output binding
OutputBinding myOutput = new OutputBinding();
Soap12BodyBinding soap12BodyOutputBinding = new Soap12BodyBinding();
soap12BodyOutputBinding.Use = SoapBindingUse.Literal;
myOutput.Extensions.Add(soap12BodyOutputBinding);
myOperationBinding.Output = myOutput;
wsdl.Bindings[0].Operations.Add(myOperationBinding);
// 1. ==> add operation to port type
Operation operation = new Operation();
operation.Name = "Add";
OperationMessage outputMessage = (OperationMessage)new OperationOutput();
outputMessage.Message = new XmlQualifiedName("tns:AddOutput");
OperationInput inputMessage = new OperationInput();
inputMessage.Message = new XmlQualifiedName("tns:AddInput");
operation.Messages.Add(inputMessage);
operation.Messages.Add(outputMessage);
wsdl.PortTypes[0].Operations.Add(operation);
// add first message
Message message1 = new Message();
message1.Name = "AddInput";
MessagePart messagePart1 = new MessagePart();
messagePart1.Name = "parameter1";
messagePart1.Type = new XmlQualifiedName("s:int");
MessagePart messagePart2 = new MessagePart();
messagePart2.Name = "parameter2";
messagePart2.Type = new XmlQualifiedName("s:int");
message1.Parts.Add(messagePart1);
message1.Parts.Add(messagePart2);
// add second message
Message message2 = new Message();
message2.Name = "AddOutput";
// add third message
MessagePart messagePart3 = new MessagePart();
messagePart3.Name = "result";
messagePart3.Type = new XmlQualifiedName("s:int");
message2.Parts.Add(messagePart3);
// 2. ==> add messages
wsdl.Messages.Add(message1);
wsdl.Messages.Add(message2);
// write the service description into a WSDL file.
wsdl.Write("empty_add.wsdl");
Console.WriteLine("WSDL file named empty_add.wsdl created successfully.");
Using version two, you have full control over all types, messages, operations, bindings, etc. and get a short and easy:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:tns="http://localhost/remote" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" targetNamespace="http://localhost/remote" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://localhost/remote" />
</wsdl:types>
<wsdl:message name="AddInput">
<wsdl:part name="parameter1" type="s:int" />
<wsdl:part name="parameter2" type="s:int" />
</wsdl:message>
<wsdl:message name="AddOutput">
<wsdl:part name="result" type="s:int" />
</wsdl:message>
<wsdl:portType name="RemoteAddServiceSoap12">
<wsdl:operation name="Add">
<wsdl:input message="tns:AddInput" />
<wsdl:output message="tns:AddOutput" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="RemoteAddServiceSoap12" type="tns:RemoteAddServiceSoap12">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="Add">
<soap12:operation soapAction="http://localhost/remote/Add" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="RemoteAddService">
<wsdl:port name="RemoteAddServiceSoap12" binding="tns:RemoteAddServiceSoap12">
<soap12:address location="http://localhost:8765/RemoteAddService.asmx" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
To create a WCF proxy for C# :
svcutil -n:*,srRemoteAddService empty_add.wsdl
Apr 30, 2008
Compiler generator CoCo/R for C#
During the preparation for a project bid for one of my customers I recently came across the CoCo/R compiler generator tool. Coco/R is a compiler generator, which takes an attributed grammar Backus-Naur-Form ( BNF) of a source language and generates a C# (and many other languages) scanner and a parser for this language.
To play around I created a small language that can speak and show message boxes. The grammer .ATG file looks the following:
COMPILER Talk
public System.Speech.Synthesis.SpeechSynthesizer ss = new System.Speech.Synthesis.SpeechSynthesizer();
void Say(string text)
{
ss.Speak(text);
}
void Show(string text)
{
System.Windows.Forms.MessageBox.Show(text);
}
IGNORECASE
// The $L option let you compile directly within your grammar
// You can comment and uncomment the line to fit your development requirements.
$LM
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
CHARACTERS
digit = "0123456789".
cr = '\r'.
lf = '\n'.
tab = '\t'.
bslash = '\\'.
quote = '"'.
chars = ANY - digit - cr - lf - tab - bslash - quote.
TOKENS
string = quote { chars | digit} quote.
IGNORE cr + lf + tab
PRODUCTIONS
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Show
=
"Show" string (. Show(t.val); .)
.
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Say
=
"Say" string (. Say(t.val); .)
.
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Statement
=
Show | Say
.
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Statements
=
Statement ';' { Statement ';' }
.
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
Talk
=
Statements
.
END Talk.
Please note the so-called semantic actions, like (. Say(t.val); .) that is executed when the corresponding token is parsed.
The code I had to write was reduced to the following:
private void btnTalk_Click(object sender, RoutedEventArgs e)
{
Parser p = new Parser(this.tbTalk.Text);
p.Parse();
tbOutput.Text = p.errors.count.ToString() + " errors";
}
Nice and easy.
Apr 22, 2008
Microsoft.TeamFoundation.WorkItemTracking.Client
string workItemStore = ConfigurationManager.AppSettings["WorkItemStore"];
store = new WorkItemStore(workItemStore);
to connect to the TFS server and then
WorkItem m_workItem = store.GetWorkItem(int.Parse(this.tbID.Text));
if (m_workItem != null)
{
lblWorkItem.Text = m_workItem.Title;
foreach (Link link in m_workItem.Links)
{
RelatedLink rl = link as RelatedLink;
if (rl != null)
{
WorkItem realtedWorkItem = m_workItem.Store.GetWorkItem(rl.RelatedWorkItemId);
list.Add(realtedWorkItem);
}
}
}
dataGridView1.DataSource = list;
to list the linked work items in a simple grid.
When you want to query for WIs it should be possible to call:
// query retrieves all work items for the specified team project
string wiqlQuery = "SELECT [System.Id], [System.WorkItemType], [System.State], [System.AssignedTo], [System.Title] FROM WorkItems WHERE [System.TeamProject] = '" + teamProjectName + "' ORDER BY [System.WorkItemType], [System.Id]";
// execute the query and retrieve a collection of workitems
WorkItemCollection workitems = store.Projects[0].Store.Query(wiqlQuery);
// loop through work items
if (workitems.Count > 0)
{
// select first Work Item
retWi = workitems[0];
}
Note: To get rid of the assembly load exception just reference the shared assemblies from the disk path and do not use the GAC ones!