Welcome to MSDN Blogs Sign in | Join | Help

TestApi v0.3 released

TestApi is a collection of test and utility API's written to make testing WPF, WinForms, .NET, and Win32 applications easy.  I made some contributions to last week's release (combinatorial variation generation).  Also new is a fault injection engine.  Previous features have included:

  • Command line parsing
  • Visual verification
  • Application control
  • Several WPF utilities

You can check it out here:  http://testapi.codeplex.com/

Posted by NathanA | 0 Comments

XAMLFest

If you're interested in what XAML can do for you today and what tooling is available, check out XAMLFest.  There's a whole series of web seminars on WPF, Silverlight, Blend, and Visual Studio.
Posted by NathanA | 0 Comments

New XAML features in .NET 4.0 Beta 1

There's a whole new XAML stack in the recently released beta 1 (download here) with a bunch of exciting new features making XAML even more expressive.  You can check out Rob's blog and Channel 9 for an overview.  I thought I'd discuss some new features for designing new types (Activities, Services, etc) in XAML.  Sorry, this isn't supported for WPF as of now.

When you fire up Visual Studio 2010 and create a new WCF or WF project, you'll see there's now a XAML file that defines your workflow or service. 

For WCF, the service is actually "loose" XAML.  It doesn't create a new type and will simply be instantiated by your service host with the equivalent of XamlServices.Load.

For WF, the workflow is defined as a new type that will be compiled as part of your project, if you look at the XAML in the new project there'll be something like this:

<p:Activity x:Class="WorkflowConsoleApplication1.Sequence1" ...

Nothing new here except x:Class is applied to a WF type instead of WPF.  Now lets add some arguments to the Activity:

<p:Activity x:Class="WorkflowConsoleApplication1.Sequence1" ...>

<x:Members>

<x:Property Name="Input" Type="p:InArgument(x:String)" />

<x:Property Name="Output" Type="p:OutArgument(x:String)" />

<x:Property Name="Temp" Type="x:String" />

...

Here's where we see some of the new XAML features.  x:Members defines a collection of new members to add to this type.  x:Property adds a property.  Name and type are specified here, visibility (public, protected, etc) can be specified with the Modifer property.  We can also see the new generics support as p:InArgument(x:String) refers to the type InArgument<string>.  All of the new language features mentioned in Rob's post can be used in this XAML.

Posted by NathanA | 0 Comments

Lots of new WCF REST resources available

A new developer center just for WCF REST is now live at MSDN:  http://msdn.microsoft.com/wcf/rest.

Plus the WCF REST Starter kit with oodles of goodies is available at Codeplex: http://www.codeplex.com/aspnet/Wiki/View.aspx?title=WCF%20REST.

There's also a forum to discuss the starter kit:  http://forums.asp.net/1180.aspx

Posted by NathanA | 0 Comments

PDC is coming

Uncloaking after a long absence, here's some of what is new and exciting for the next release of WCF and WF:  everything can be done in XAML. 

http://blogs.windowsclient.net/rob_relyea/archive/2008/09/30/pdc08-xaml-talk.aspx

http://channel9.msdn.com/pdc2008/TL36/

Posted by NathanA | 0 Comments

WCF Web Programming Help Page

When developing a WCF service using the new web programming features, it's natural to make sure all the basics are taken care of by entering the service address into a browser.  When the service is running correctly, this page is returned:

This indicates the service is running but little else.  There's lots of other information that would be useful to include, maybe something like this (I'm not an html wizard so this could be greatly improved:)

 

This is made possible by including an OperationContract like this in the ServiceContract:

[WebInvoke(UriTemplate = "*", Method = "*")]

[OperationContract]

Message Help(Message m);

 

The method can be named anything and UriTemplate and Method can be tweaked to serve custom help for only certain situations.  As shown, any message routed to the service that doesn't match another operation contract will call Help.  To implement this method I created two classes, WebHttpHelpPageGenerator and WebHttpHelpPageMessage.  WebHttpHelpPageGenerator handles collecting the information to display and WebHttpHelpPageMessage derives from Message and handles formatting that information into html.  These are used to implement Help like this:

public Message Help(Message m)

{

    return WebHttpHelpPageGenerator.GenerateHelpPage();

}

WebHttpHelpPageGenerator.GenerateHelpPage is able to accomplish its task by using OperationContext.Current.EndpointDispatch.ContractName and OperationContext.Current.Host.Description.Endpoints to find the current ServiceEndpoint which contains a list of Operations and the CLR type of the contract:

ServiceEndpointCollection endpoints = OperationContext.Current.Host.Description.Endpoints;

OperationDescriptionCollection operations = null;

Type contract = null;

foreach (ServiceEndpoint endpoint in endpoints)

{

        if (endpoint.Contract.Name == OperationContext.Current.EndpointDispatcher.ContractName)

        {

             contract = endpoint.Contract.ContractType;

             operations = endpoint.Contract.Operations;

             break;

        }

} 

So with that list and a little reflection all the necessary information can be exctracted:

message.TitleTextString = contract.Name;

foreach (OperationDescription operation in operations)

{

      WebGetAttribute get = operation.Behaviors.Find<WebGetAttribute>();

      WebInvokeAttribute invoke = operation.Behaviors.Find<WebInvokeAttribute>();

 

      if (get == null && invoke == null) continue;

 

      MethodInfo method = contract.GetMethod(operation.Name);

      OperationInfo info = new OperationInfo

      {

           OperationName = operation.Name,

           Method = get != null ? "GET" : invoke.Method,

           BodyStyle = get != null ? get.BodyStyle.ToString() : invoke.BodyStyle.ToString(),

           UriTemplate = get != null ? get.UriTemplate : invoke.UriTemplate,

           ReturnType = method.ReturnType.ToString(),

           Parameters = GetFormattedParameters(method.GetParameters()),

           RequestFormat = get != null ? get.RequestFormat.ToString() : invoke.ResponseFormat.ToString(),

           ResponseFormat = get != null ? get.ResponseFormat.ToString() : invoke.ResponseFormat.ToString()

       };

 

       info.OperationName = operation.Name;

       message.Operations.Add(info);                 

}

OperationInfo is just a helper class to encapsulate all the data collected.  Finally the new WebOperationContext class is used to set the content type to text/html:

WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"; 

This builds a general purpose framework that can be called from any service using the new web programming features, though I'm sure I missed plenty of corner cases (like async programming.)

Posted by NathanA | 0 Comments

WCF Web Programming or: How I Learned to Stop Worrying and Love Uri Templates

Using WCF in web programming scenarios is much simplified in Orcas beta 2 (see http://hyperthink.net/blog/CategoryView,category,indigo.aspx and scroll down for more discussions).  Maybe you want to write an app that searches Flickr, how can you use WCF?  Well, define an interface that exposes the functionality you need:

[ServiceContract]

interface IFlickrSearch

{

        [WebGet(UriTemplate="services/rest/?method=flickr.photos.search&api_key={appId}&tags={searchTerms}&extras={extras}&per_page={perPage}",

           BodyStyle=WebMessageBodyStyle.Bare)]

        [OperationContract]

        [XmlSerializerFormat]

        rsp Search(string appId, string searchTerms, string extras, int perPage);

}

The Flickr API is very rich, so this is just the tip of the iceberg, but just this little bit of code accomplishes a lot.  We have all the WCF v1 attributes (ServiceContract, OperationContract) and some new stuff.  WebGet says the request will be a GET and UriTemplate describes how the parameters will be turned into the uri for the request.  This provides a great deal of flexibility in defining your interface to the service you're programming against.  The Bare BodyStyle specifies to the serializer there won't be wrapper element named SearchResponse on the response.  XmlSerializerFormat is another holdover specifying the XmlSerializer, and rsp is a type generated with xsd.exe to deserialize the response. 

Now we're ready to call Flickr:

WebChannelFactory<IFlickrSearch> factory =

                new WebChannelFactory<IFlickrSearch>(new Uri("http://api.flickr.com"));

               

IFlickrSearch channel = factory.CreateChannel();

rsp flickrRsp = channel.Search(AppId, searchTerms, Extras, perPage);

And that's it.

 Maybe you're saying XmlSerializer is way too 20th century and you'd like use something more 21st, like XLinq.

[ServiceContract]

interface IFlickrSearch

{

        [WebGet(UriTemplate = "services/rest/?method=flickr.photos.search&api_key={appId}&tags={searchTerms}&extras={extras}&per_page={perPage}",

           BodyStyle = WebMessageBodyStyle.Bare)]

        [OperationContract]

        XElement Search(string appId, string searchTerms, string extras, int perPage);

}

We've just taken out the XmlSerializerFormat attribute and replaced the rsp type with XElement.  Now we can use Linq and turn the Flickr search into a SyndicationFeed (another new WCF Orcas feature):

SyndicationFeed feed = new SyndicationFeed();

feed.Title = new TextSyndicationContent("Flickr search");

 

feed.Items =

     from photos in flickrXml.Elements("photos").Elements("photo")

     select SyndicationItemFromXElement(photos);

Just add this to a service and now you have a Flickr search you can subscribe to in the feed aggregator of your choice.

Posted by NathanA | 2 Comments

Getting started with LINQ

Here's a great site with a bunch of samples if you've said to yourself "I'm pretty sure I can do this with LINQ, but I'm not quite sure how."

101 LINQ Samples

Posted by NathanA | 1 Comments

Custom SOAP Headers: WCF and ASMX

First the good news, WCF clients should just work with ASMX services that use custom SOAP headers.

Now the not so good news, ASMX clients will work with WCF services that use headers, but the object model is pretty funky.  Say you want to do something really crazy like have a header of type string.  The ASMX client will represent that header with a class that looks like this:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2001/XMLSchema")]
[System.Xml.Serialization.XmlRootAttribute("StringHeader", Namespace="http://xwsinterop/soapwsdl/headers", IsNullable=true)]
public partial class @string : System.Web.Services.Protocols.SoapHeader {
   
    private string[] textField;
   
    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string[] Text {
        get {
            return this.textField;
        }
        set {
            this.textField = value;
        }
    }
}

To use this class, assign a new string array of length 1 to Text and then assign the value of the header to that element and it will work as expected.  These sorts of classes will be generated by ASMX for any simple type, the workaround is to use wrapper classes around the headers on the WCF side.  This will result in a somewhat clunky OM, but it will make sense.

Posted by NathanA | 5 Comments

Custom SOAP Headers: WCF and Java

First the good news, WCF clients should just work with Java services that use custom SOAP headers.

Now the not so good news, Java proxies generated from the default WCF WSDL won't include the SOAP headers in the object model.  The root problem is most Java platforms represent headers in WSDL differently than WCF.  In WCF, the body and the headers are defined in different WSDL message elements:

<wsdl:message name="OneHeaderIntRequest">
<wsdl:part name="stringBody" element="tns:stringBody" />
</wsdl:message>
<wsdl:message name="OneHeaderIntRequest_Headers">
<wsdl:part name="IntHeader" element="tns:IntHeader" />
</wsdl:message>

but for most Java platforms, only one message with multiple parts is defined:

<message name="OneHeaderIntRequest">
<part element="s0:stringBody" name="parameters" />
<part element="s0:IntHeader" name="IntHeader" />
</message>

The workaround is to modify the WCF WSDL to mirror the Java-style WSDL (eliminate the OneHeaderIntRequest_Headers message and move the IntHeader part into the OneHeaderIntRequest message in this case).  Unfortunately this is a manual process.  Now to serve this wsdl requires setting the ExternalMetadataLocation property on the ServiceMetadataBehavior either in a service host or in config.

 

 

Posted by NathanA | 1 Comments

How do I get a DateTime from a UNIX timestamp?

Often when consuming data from a web site, it will represent time with a UNIX timestamp.  This is the number of seconds since January 1, 1970.  It would be nice to turn this into a System.DateTime, but how?

DateTime FromUnixTime(Int64 unixTime)

{

DateTime time = new DateTime(unixTime * 10000000);

time = time.AddYears(1969);

return time;

}

The DateTime constructor takes the number of 100 nanosecond ticks since January 1, 0001, so multiplying by 10000000 translates seconds into 100 nanosecond intervals.  But the Unix era begins in 1970 and DateTime in 1, so to translate that we add 1969 years.

Posted by NathanA | 2 Comments

Coming soon...

I have done much posting in more or less forever, but I have some new stuff on deck.  In the meantime, check out the recent posts at Steve Maine's blog for some of the stuff I've been working on.
Posted by NathanA | 0 Comments

WCF and eBay

eBay provides a very rich, though very complicated, SOAP API.  It is possible to use WCF with eBay, but it takes a few tricks.  First read this article.  I'll wait.  Ok, since that didn't scare you away I'll continue.  Everything there is still necessary except the custom message encoder for removing the quotes around the content type.  In fact the basicHttpBinding produced by svcutil.exe is just fine, though bumping up some of the quotas (maxNameTableCharCount, maxBufferSize, maxReceivedMessageSize) might not hurt.  Now calling GeteBayOfficialTime just works, but graduating to say GetItem, there's another problem.  GetItem returns a GetItemResponseType which derives from AbstractResponseType.  After successfully calling GetItemResponseType, all the fields it inherits are correctly populated but the fields it defines haven't been.  Looking at the response on the wire, those fields are there, for some reason they weren't deserialized.  The problem is eBay defined the schema for AbstractResponseType with an xs:any, so the code generated for this type includes an array of XmlElements with the XmlAny attribute:

[System.Xml.Serialization.XmlAnyAttribute(Order=12)]

public System.Xml.XmlElement[] Any

When the response from eBay arrives the XmlSerializer happily begins populating all the fields in AbstractResponseType and anything it doesn't recognize gets put into Any.  Now when it's time to populate the fields defined in GetItemResponseType there's no xml left.  Given this knowledge it's an easy fix, but unfortunately it involves manually editing the generated proxy.  All that's necessary is to change the XmlAnyAttribute to an XmlIgnoreAttribute.  Now upon receiving the response, the XmlSerializer "saves" any elements that don't map to AbstractResponseType and uses them to populate GetItemResponseType.

Posted by NathanA | 1 Comments
More Posts Next page »
 
Page view tracker