Sergey Zwezdin


Microsoft Regional Director

Microsoft MVP
Handling authentication-specific issues for AJAX-calls

For modern web-applications has become the usual to use AJAX when you create user interfaces. However, it makes our headache from time to time. And often these difficulties are associated with authentication and processing such requests on the client.

Read more

Using custom domain with Office 365

This blog post contains steps to linking cutom domain to Office 365.

Read more

Using Visual Studio 2010 in different environments

Do you like to setup a Visual Studio with the personal preferences? Unfortunately, in some situations we are forced to change development environment settings according to that context in which at present we are. Let's talk about automation of this process.

Read more

Multitasking at Windows Phone 7 Series

One of most question, discussed with consideration of Windows Phone 7 Series is multitasking. As it was clarified, this question calls concern in a great number of users and developers. Let's more in detail consider this question.

Read more

Windows Phone 7 Series - what the new mobile platform hides in itself

By this post I wish to open a series of articles about development for Windows Phone 7 Series. We will start that we will consider philosophy of a new platform from the point of view of the developer.

Read more

My blog has been updated

My blog has been updated. Welcome! Don't forget to update your RSS readers.

Read more

Use of enum type in ADO.NET Data Services

This the autumn was possible to communicate about ADO.NET Data Services with the Izhevsk developers community. Except other discussed questions, we have started talking about use of enum type as a part of entity which is used in service based on ADO.NET Data Services. As after that in this question was interested some more person, I decide to take out this information here.

The problem consists in the following. We will assume have decided to create service ADO.NET Data Services and to use in its source the entity containing a field of enum type. Having accessed to such service it is possible to see a strange error.

It is possible to look details of this error. For this purpose it is necessary to setup service.

[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class WebDataService1 : DataService<MyDataContext>
{

Having accessed to service again, we will see an error which says that enum type cannot be used in entities for similar services. Unfortunately, this annoying defect in ADO.NET Data Services can seriously impair a life of developers. Let's try solve this problem.

For this purpose we will create entity and enum type which we will use in service:

public enum StateEnum
{
    Normal = 1,
    Error = 2
}
 
[DataServiceKey("ID")]
public class SampleEntity
{
    public int ID { get; set; }
 
    public string Name { get; set; }
 
    public StateEnum State
    {
        get;
        set;
    }
}

Now we will create own data context and standard service ADO.NET Data Services.

public class MyDataContext
{
    private static readonly IEnumerable<SampleEntity> Entities = new List<SampleEntity>()
{

new SampleEntity()

{ID = 1, Name = "Name1", State = StateEnum.Normal},

new SampleEntity()

{ID = 2, Name = "Name2", State = StateEnum.Error},

new SampleEntity()

{ID = 3, Name = "Name3", State = StateEnum.Normal},

new SampleEntity()

{ID = 4, Name = "Name4", State = StateEnum.Normal},

new SampleEntity()

{ID = 5, Name = "Name5", State = StateEnum.Normal},

};
 
    public IQueryable<SampleEntity> Data
    {
        get
        {
            return Entities.AsQueryable<SampleEntity>();
        }
    }
}

It is clear, that with such service we will receive an error which saw at the beginning. To avoid an error we will use IgnoreProperties attribute.

[DataServiceKey("ID")]
[IgnoreProperties("State")]
public class SampleEntity
{
    public int ID { get; set; }
 
    public string Name { get; set; }
 
    public StateEnum State
    {
        get { return (StateEnum)StateValue; }
        set { StateValue = (int)value; }
    }
}

Great! The error has disappeared, but thus value of the given property is not transferred to the client.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
<feed xml:base="http://localhost:4321/WebDataService1.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
    <title type="text">Data</title> 
    <id>http://localhost:4321/WebDataService1.svc/Data</id> 
    <updated>2009-11-29T06:06:57Z</updated> 
    <link rel="self" title="Data" href="Data" /> 
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(1)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:06:57Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(1)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">1</d:ID> 
                <d:Name>Name1</d:Name> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(2)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:06:57Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(2)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">2</d:ID> 
                <d:Name>Name2</d:Name> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(3)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:06:57Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(3)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">3</d:ID> 
                <d:Name>Name3</d:Name> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(4)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:06:57Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(4)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">4</d:ID> 
                <d:Name>Name4</d:Name> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(5)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:06:57Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(5)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">5</d:ID> 
                <d:Name>Name5</d:Name> 
            </m:properties>
        </content>
    </entry>
    </feed>

Value of enum type is an integer. It is simple type which it is possible to transfer via service. Thus, we do small addition to this entity.

[DataServiceKey("ID")]
[IgnoreProperties("State")]
public class SampleEntity
{
    public int ID { get; set; }
 
    public string Name { get; set; }
 
    public int StateValue { get; set; }
 
    public StateEnum State
    {
        get { return (StateEnum)StateValue; }
        set { StateValue = (int)value; }
    }
}

After that, the service working with specified entity will ignore State property, but thus on the client will be transferred StateValue. It is easy to be convinced of it if to access to service through a browser.

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
<feed xml:base="http://localhost:4321/WebDataService1.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
    <title type="text">Data</title> 
    <id>http://localhost:4321/WebDataService1.svc/Data</id> 
    <updated>2009-11-29T06:13:47Z</updated> 
    <link rel="self" title="Data" href="Data" /> 
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(1)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:13:47Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(1)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">1</d:ID> 
                <d:Name>Name1</d:Name> 
                <d:StateValue m:type="Edm.Int32">1</d:StateValue> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(2)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:13:47Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(2)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">2</d:ID> 
                <d:Name>Name2</d:Name> 
                <d:StateValue m:type="Edm.Int32">2</d:StateValue> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(3)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:13:47Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(3)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">3</d:ID> 
                <d:Name>Name3</d:Name> 
                <d:StateValue m:type="Edm.Int32">1</d:StateValue> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(4)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:13:47Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(4)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">4</d:ID> 
                <d:Name>Name4</d:Name> 
                <d:StateValue m:type="Edm.Int32">1</d:StateValue> 
            </m:properties>
        </content>
    </entry>
    <entry>
        <id>http://localhost:4321/WebDataService1.svc/Data(5)</id> 
        <title type="text" /> 
        <updated>2009-11-29T06:13:47Z</updated> 
        <author>
        <name /> 
        </author>
        <link rel="edit" title="SampleEntity" href="Data(5)" /> 
        <category term="WebApplication69.SampleEntity" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
        <content type="application/xml">
            <m:properties>
                <d:ID m:type="Edm.Int32">5</d:ID> 
                <d:Name>Name5</d:Name> 
                <d:StateValue m:type="Edm.Int32">1</d:StateValue> 
            </m:properties>
        </content>
    </entry>
</feed>

The last, that it is necessary to make is to inform client library on, how to use similar fields. For this purpose on the client side we declare the necessary enum type, in a partial class we will add the necessary property and we will specify IgnoreProperties attribute.

public enum StateEnum
{
    Normal = 1,
    Error = 2
}
 
[IgnoreProperties("State")]
public partial class SampleEntity
{
    public StateEnum State
    {
        get { return (StateEnum)StateValue; }
        set { StateValue = (int)value; }
    }
}

Now at the client side it is possible to access to the necessary property and to receive value of enum type.

class Program
{
    static void Main(string[] args)
    {
        var context = new MyDataContext(new Uri(@"http://localhost:4321/WebDataService1.svc/"));
        foreach (var entity in context.Data)
        {
            Console.WriteLine(entity.State);
        }
        Console.Read();
    }
}

 

Certainly, the presented decision does not pretend to be the elegant decision, but can be usable in some cases.

Source:

ADO.NET Data Services 1.5: server driven paging.

We continue to consider new possibilities of ADO.NET Data Services 1.5 and today we will look possibility of compulsory breakdown of data into pages.

Possibility of breakdown of data on pages already was present at first version of Astoria. For these purposes it was possible to construct query by means of Take/Skip operators. Changing values of these parametres it was possible to get paginal access to data from the client. Nevertheless, at the access to a collection without parametres service returned completely all collection. The described behaviour seems quite logical, but it not always is desirable. For example, if in a collection the considerable quantity of objects the acceess to such collection will by all means entail the raised loading on a server contains. Therefore in version 1.5 the decision on addition of possibility of compulsory breakdown on pages was accepted.

To enable of the described possibility it is necessary to define additional behaviour in configuration of service. In particular SetEntitySetPageSize method which allows to define the size of page for each collection is necessary for us.

public class WebDataService : DataService<NorthwindEntities>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);
    
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        config.SetEntitySetPageSize("Categories", 5);
    }
}

In case of described above service, at the access to Categories collection data will be broken into pages on five objects.

Server Driven Paging

Apparently, for the access to the following page it is necessary to use a $skiptoken keyword. In this case URI format will look as follows:

http://.../WebDataService.svc/Categories?$skiptoken=5

The given functionality also is supported and in a client proxy. At the usual access to a collection the specified number of objects will be given out the client only. For the access to other pages it is necessary to use Skip() method.

var client = new NorthwindEntities(new Uri(@"..."));
var q = from c in client.Categories.Skip(2)
        select c;
 
foreach (var item in q)
{
    // ..
}
ADO.NET Data Services 1.5: projections.

Recently I’ve started discussion about ADO.NET Data Services 1.5. I spoke about main trends in this project. Now I want to say about some details. Here we will speak about possibilities to create projections of data in version 1.5 of ADO.NET Data Services.

Necessity of creation of projections was present at first version of Astoria. However, as we know, time and resources are limited, therefore such possibility has appeared only in version 1.5. Possibility of creation of projections is necessary in those situations when an entity, containing in collections on service contain a considerable quantity of fields, and some fields are necessary to the client only. In this case the client is compelled to load all fields of these objects and by that to generate the superfluous traffic and increasing time of performance of queries.

In version 1.0 it was offered to solve a problem by division of the big entity on a little bit small and to work with them separately. Certainly, such approach creates many problems. For example, in such situation it is required to make additional efforts in case of editing of such collections. Besides, the quantity of collections of data on service can essentially increase. In this case the logical decision arises - to ask for service to return not all fields of objects, but only what it is necessary directly in URI.

The idea of work of the mechanism of projections consists in it in ADO.NET Data Services 1.5. Every time when it is necessary to return a specific set of fields, we set it obviously in URI. Thus other fields are ignored and not transferred to the client.

For execute of similar query there was a new "select" keyword. For example, if it is necessary to select two fields ProductName and UnitPrice it is necessary to execute the following query:

http://../WebDataService.svc/Products()?$select=ProductName,UnitPrice

Similarly, if it is necessary to select all fields, having ignored this operator or having specified as value "*":

http://../WebDataService.svc/Products()?$select=*

In some situations possibility of creation of projections can be undesirable. In this case it can be switch off, using additional parametres in service configuration. For this purpose in DataServiceConfiguration class there was property DataServiceBehavior which allows to adjust behaviour of service. In this case we are interested in AcceptProjectionRequests property.

public class WebDataService : DataService<NorthwindEntities>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);
 
        config.DataServiceBehavior.AcceptProjectionRequests = true;
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
    }
}

At use of a client proxy possibility of creation of projections also can be used conveniently. For this purpose it is necessary to construct LINQ-query where in Select section to specify necessary fields.

var client = new NorthwindEntities(new Uri(@"http://.../WebDataService.svc/"));
var q = from c in client.Categories
        select new { c.CategoryName, c.Description };

This functionality was very necessary in first version ADO.NET Data Services and now it was is added. And now we can use services even more effectively.

Displaying of progress of downloading data in WCF services

Platform Windows Communication Foundation can be used not only for a simple operations call, but also for transfer of big parts of data (for example, files in some mbyte). Sometimes such scenarios are applicable and on slow channels. In this case an indicator of executing of operation (progress bar) is necessary.

For simplicity we will use BasicHttpBinding binding. The key moment at implementation of the given scenario is setting of TransferMode parameter to Streamed value. Thus, data will be transferred as a stream.

After that we will define the contract. It is required to transfer a file name, its size and contents to the client side.

[ServiceContract]
public interface IFileTransferService
{
    [OperationContract]
    RemoteFileInfo DownloadFile(DownloadRequest request);
}
 
[MessageContract]
public class DownloadRequest
{
    [MessageBodyMember]
    public string FileName;
}
 
[MessageContract]
public class RemoteFileInfo : IDisposable
{
    [MessageHeader(MustUnderstand = true)]
    public string FileName;
 
    [MessageHeader(MustUnderstand = true)]
    public long Length;
 
    [MessageBodyMember(Order = 1)]
    public Stream FileByteStream;
 
    public void Dispose()
    {
        if (FileByteStream != null)
        {
            FileByteStream.Close();
            FileByteStream = null;
        }
    }
}

Apparently, DownloadFile operation returns RemoteFileInfo object which contains the necessary information.

public class FileTransferService : IFileTransferService
{
    public RemoteFileInfo DownloadFile(DownloadRequest request)
    {
        var filePath = request.FileName;
        var fileInfo = new FileInfo(filePath);
 
        if (fileInfo.Exists==false)
        {
            throw new FileNotFoundException("File not found", request.FileName);
        }
 
        var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
 
        var result = new RemoteFileInfo
                         {
                             FileName = request.FileName, 
                            Length = fileInfo.Length, 
                            FileByteStream = stream
                         };
 
        return result;
    }
}

Now it is necessary to host service

class Program
{
    static void Main()
    {
        var myServiceHost = new ServiceHost(typeof(FileService.FileTransferService));
        myServiceHost.Open();
 
        Console.ReadKey();
 
        myServiceHost.Close();
    }
}

Thus the configuration file will have the following data.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="FileTransferServicesBinding" transferMode="Streamed" messageEncoding="Mtom" maxReceivedMessageSize="20134217728" />
            </basicHttpBinding>
        </bindings>
        <services>
            <service behaviorConfiguration="MyServiceTypeBehaviors" name="FileService.FileTransferService">
                <endpoint address="getfile"
                  binding="basicHttpBinding"
                  bindingConfiguration="FileTransferServicesBinding"
                  contract="FileService.IFileTransferService" />
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost/" />
                    </baseAddresses>
                </host>
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="MyServiceTypeBehaviors">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

Now it is necessary to create a client side.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="fileBinding" maxReceivedMessageSize="20134217728" messageEncoding="Mtom" transferMode="Streamed" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost/getfile"
                                binding="basicHttpBinding"
                                bindingConfiguration="fileBinding"
                                contract="Client.FileTransferClient.IFileTransferService" />
        </client>
    </system.serviceModel>
</configuration>

After generation of a client proxy it looks as follows.

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class FileTransferServiceClient : 
    System.ServiceModel.ClientBase<Client.FileTransferClient.IFileTransferService>, 
    Client.FileTransferClient.IFileTransferService
{
   public FileTransferServiceClient()
   {
   }
   
   public FileTransferServiceClient(string endpointConfigurationName) : 
           base(endpointConfigurationName)
   {
   }
   
   public FileTransferServiceClient(string endpointConfigurationName, string remoteAddress) : 
           base(endpointConfigurationName, remoteAddress)
   {
   }
   
   public FileTransferServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
           base(endpointConfigurationName, remoteAddress)
   {
   }
   
   public FileTransferServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
           base(binding, remoteAddress)
   {
   }
   
   Client.FileTransferClient.RemoteFileInfo Client.FileTransferClient.IFileTransferService.DownloadFile(Client.FileTransferClient.DownloadRequest request)
   {
       return base.Channel.DownloadFile(request);
   }
}

Let's create more convenient DownloadFile method.

public long DownloadFile(ref string fileName, out System.IO.Stream fileByteStream)
{
    Client.FileTransferClient.DownloadRequest inValue = new Client.FileTransferClient.DownloadRequest();
    inValue.FileName = FileName;
    Client.FileTransferClient.RemoteFileInfo retVal = ((Client.FileTransferClient.IFileTransferService)(this)).DownloadFile(inValue);
    FileName = retVal.FileName;
    FileByteStream = retVal.FileByteStream;
    return retVal.Length;
}

Now we should receive this stream and read out from it the information in the portions.

var client = new FileTransferClient.FileTransferServiceClient();
 
Stream inputStream;
long length = client.DownloadFile(ref fileName, out inputStream);
 
using (var writeStream = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write))
{
    const int bufferSize = 2048;
    var buffer = new byte[bufferSize];
 
    do
    {
        int bytesRead = inputStream.Read(buffer, 0, bufferSize);
        if (bytesRead == 0)
        {
            break;
        }
 
        writeStream.Write(buffer, 0, bytesRead);
 
        progressBar1.Value = (int)(writeStream.Position * 100 / length);
    }
    while (true);
 
    writeStream.Close();
}
 
inputStream.Dispose();
client.Close();

Great! Now we have received the application which will display progress of downloading data on the client. Similarly it is possible to make uploading data to a server. If this infomation is interesting to you I recommend to read more detailed article.

Source code:

More Posts Next page »