I have a connected WCF service, where the client configuration code is as below:
var method = typeof(XmlSerializer).GetMethod("set_Mode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
method.Invoke(null, new object[] { 1 });
BasicHttpsBinding httpBd = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
httpBd.MaxReceivedMessageSize = Int32.MaxValue;
httpBd.MaxBufferSize = Int32.MaxValue;
var client = new FindServicePortTypeClient(httpBd,
new EndpointAddress(_settings.Url));
var bd = client.Endpoint.Binding as BasicHttpsBinding;
bd.Security.Mode = BasicHttpsSecurityMode.Transport;
bd.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
client.ClientCredentials.UserName.UserName = _settings.User;
client.ClientCredentials.UserName.Password = _settings.Password;
On the service I have to configure some performance metrics like "relation deepness". How can I achieve this
In WCF, you can use ServiceThrottlingBehavior to control WCF service performance.Using this behavior, you can fine-tune the performance of your Windows Communication Foundation application.
You can configure the values of these properties in the configuration file.
<behaviors>
<serviceBehaviors>
<behavior name="Throttled">
<serviceThrottling
maxConcurrentCalls="1"
maxConcurrentSessions="1"
maxConcurrentInstances="1"
/>
<serviceMetadata
httpGetEnabled="true"
httpGetUrl=""
/>
</behavior>
</serviceBehaviors>
</behaviors>
MaxConcurrentSessions:The maximum number of sessions a service host accepts. The default is 100 times the processor count.
MaxConcurrentCalls:The upper limit of active messages in the service. The default is 16 times the processor count.
MaxConcurrentInstances:The maximum number of InstanceContext objects in the service at one time. The default is the sum of the value of MaxConcurrentSessions and the value of MaxConcurrentCalls.
Windows Communication Foundation includes a large set of performance counters to help you gauge your application's performance.For more information about Performance Counters,Please refer to the following link:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/performance-counters/
Related
Summary
A WCF service hosted in IIS has only 1 method that takes 1 second to complete (Thread.Sleep in sample code). When 5 'clients' hammer the server with requests average response times is 1 second, 10 clients - around 2 seconds and with 20 clients the performance drops below the floor. I have tried all kind of settings and nothing helps.
I think the problem is in WCF (MS tried to make it fail-safe and put a lot of safeguards from developers): it tries to use as few threads as possible and thus the performance suffer.
Detailed description
Code
I have a very simple WCF service hosted in IIS:
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Threading;
namespace WCFPerf
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "Test")]
Stream DoWork(Stream s);
}
public class Service1 : IService1
{
public Stream DoWork(Stream s)
{
Thread.Sleep(1000); // simulate work
return s;
}
}
}
The configuration file:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime />
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="WCFPerf.Service1">
<endpoint address="" behaviorConfiguration="web" binding="customBinding" bindingConfiguration="" contract="WCFPerf.IService1" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:57676/Service1.svc" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<customBinding>
<binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00">
<webMessageEncoding />
<httpTransport manualAddressing="true" />
</binding>
</customBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling maxConcurrentCalls="200" maxConcurrentSessions="200" maxConcurrentInstances="200" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.net>
<connectionManagement>
<add address="*" maxconnection="2000" />
</connectionManagement>
</system.net>
</configuration>
The test suit:
void Main()
{
var numberOfThreads = new[] {5, 10, 20, 30};
var table = new List<ResultInfo>();
foreach (var threadNumber in numberOfThreads)
{
var tasks = new List<Task<List<double>>>();
for (var i = 0; i < threadNumber; i++)
{
tasks.Add(Task<List<double>>.Factory.StartNew(() =>
{
var results = new List<double>();
for (var j = 0; j < 5; j++)
{
results.Add(SendRequest());
}
return results;
}));
}
Task.WaitAll(tasks.ToArray());
var allResults = tasks.SelectMany(t => t.Result);
table.Add(new ResultInfo{ Threads = threadNumber, Avg = allResults.Average().ToString("F2"), Min = allResults.Min().ToString("F2"), Max = allResults.Max().ToString("F2") });
}
table.Dump();
}
public double SendRequest()
{
var stopwatch = new Stopwatch();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(#"http://localhost:8081/");
stopwatch.Start();
var t = client.PostAsync("WCFPerf/Service1.svc/Test", new StringContent("123")).Result;
stopwatch.Stop();
return stopwatch.Elapsed.TotalSeconds;
}
}
public class ResultInfo
{
public int Threads {get;set;}
public string Avg {get;set;}
public string Min {get;set;}
public string Max {get;set;}
}
The test results are very inpredictable, but always there is a bad number:
This run I changed execution time from 1 second to 5 seconds just to demonstrate that the diff (2x times, 3x times, etc.) is relative, not absolute. Also notice that 'warm up' helps, but just a little bit.
Comments
During all my testing (and I did about 100 runs of different kind) the maximum amount of threads reported by Windows Task Manager in w3wp process was 54. I am using Core i3 CPU with 2 physical cores and 4 logical cores, 12 Gb RAM, running under Windows 8.1 and .Net 4.5. Memory print of the process always grows, but very slowly, the highest value was around 110 Mb.
dotTrace reports that about 7% of time is spent in my code and everything else - in system code.
I have tried doing the following:
In C:\Windows\Microsoft.NET\Framework\v4.0.30319\Aspnet.config:
<system.web>
<applicationPool maxConcurrentRequestsPerCPU="5000" maxConcurrentThreadsPerCPU="0" requestQueueLimit="5000"/>
</system.web>
In C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config
<system.net>
<connectionManagement>
<add address = "*" maxconnection = "400" />
</connectionManagement>
</system.net>
<system.web>
<processModel autoConfig="false" maxWorkerThreads="80" maxIoThreads="80" />
<httpRuntime minFreeThreads="10" minLocalRequestFreeThreads="10" />
Links: Web Settings Schema, Element, applicationPool maxConcurrentRequestsPerCPU, Element, Thread Throttling in IIS-hosted WCF, processModel Element, httpRuntime Element, ASP Registry Entries (IIS 6.0)
Ideas
My rationale (how it is supposed to work): while we have enough memory for every IIS/WCF creates a new thread for every request. For example when we have 40 'clients' connecting to the server - there will be about 45 threads in w3wp process (40 working threads and a few others for good measure). Because all my 'clients' wait for response before sending next request, there might be a little difference in response times (like 20-30%, not 2x or even 10x I see now).
The problems (as I see them):
There are not enough threads (only 54 threads for 70 clients)
There is some kind of queue, because already at 20 'clients' the average response time is at least twice longer than the actual logic
There is a non deterministic behavior, because results differ greatly from run to run
I have found an answer in kb aritcle number 2538826, the sample code also can be found in this blog post (with some additional information like how to add perf counters and write load test).
This solution will help you only if you have the described behavior (check provided links for details): number of threads you use (Thread count perf counter) does not scale as fast as your requests. The picture from KB article:
So the fix is to use some other way to create threads... and what is a better way than yo use a ThreadPool?
You need these two classes:
public class WorkerThreadPoolSynchronizer : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
// WCF almost always uses Post
ThreadPool.QueueUserWorkItem(new WaitCallback(d), state);
}
public override void Send(SendOrPostCallback d, object state)
{
// Only the peer channel in WCF uses Send
d(state);
}
}
and
[AttributeUsage(AttributeTargets.Class)]
public class WorkerThreadPoolBehaviorAttribute : Attribute, IContractBehavior
{
private static WorkerThreadPoolSynchronizer synchronizer = new WorkerThreadPoolSynchronizer();
void IContractBehavior.AddBindingParameters(
ContractDescription contractDescription,
ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{
}
void IContractBehavior.ApplyClientBehavior(
ContractDescription contractDescription,
ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
}
void IContractBehavior.ApplyDispatchBehavior(
ContractDescription contractDescription,
ServiceEndpoint endpoint,
DispatchRuntime dispatchRuntime)
{
dispatchRuntime.SynchronizationContext = synchronizer;
}
void IContractBehavior.Validate(
ContractDescription contractDescription,
ServiceEndpoint endpoint)
{
}
}
And then apply the attribute to your service:
[WorkerThreadPoolBehavior] // this is what changed
public class Service1 : IService1
{
public Stream DoWork(Stream s)
{
Thread.Sleep(1000); // simulate work
return s;
}
}
I'm trying to use the API REST of Windows Azure for creating a virtual machine deployment. However, I've got a problem when trying to specify an OS image in the following XML file:
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Name>SomeName</Name>
<DeploymentSlot>Production</DeploymentSlot>
<Label></Label>
<RoleList>
<Role i:type="PersistentVMRole">
<RoleName>SomeName</RoleName>
<OsVersion i:nil="true"/>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type="WindowsProvisioningConfigurationSet">
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
<ComputerName>SomeName</ComputerName>
<AdminPassword>XXXXXXXXXX</AdminPassword>
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
<ResetPasswordOnFirstLogon>false</ResetPasswordOnFirstLogon>
</ConfigurationSet>
<ConfigurationSet i:type="NetworkConfigurationSet">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>3389</LocalPort>
<Name>RemoteDesktop</Name>
<Protocol>tcp</Protocol>
</InputEndpoint>
</InputEndpoints>
</ConfigurationSet>
</ConfigurationSets>
<DataVirtualHardDisks/>
<Label></Label>
<OSVirtualHardDisk>
<MediaLink>¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿???????????????</MediaLink>
<SourceImageName>¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿??????????????????</SourceImageName>
</OSVirtualHardDisk>
</Role>
</RoleList>
</Deployment>`
I need the MediaLink (URI of the OS image) and the SourceImageName (Canonical name of the OS image). My question is, the web portal provides several PREDEFINED images but I cannot determine the URI and the canonical name of them. Will I be forced to create my own OS image and upload it to any of the storage services under my Windows Azure account?
To get these parameters, you could perform List OS Images Service Management API operation on your subscription.
UPDATE
Please discard some of my comments below (sorry about those). I was finally able to create a VM using REST API :). Here're some of the things:
<MediaLink> element should specify the URL of the VHD off of which your VM will be created. It has to be a URL in one of your storage account in the same subscription as your virtual machine cloud service. So for this, you could specify a URL like: https://[yourstorageaccount].blob.core.windows.net/[blobcontainer]/[filename].vhd where [blobcontainer] would be the name of the blob container where you would want the API to store the VHD while the [filename] is any name that you want to give to your VHD. What REST API does is that it copies the source image specified in the <SourceImageName> and saves it at the URI specified in the <MediaLink> element.
Make sure that your Service and Storage Account where your VHD will be stored are in the same data center/affinity group. Furthermore that data center should be able to support Virtual Machines. It turns out that not all data centers support Virtual Machines.
Order of XML element is of utmost importance. You move one element up or down would result in 400 error.
Based on my experimentation, here's the code:
private static void CreateVirtualMachineDeployment(string subscriptionId, X509Certificate2 cert, string cloudServiceName)
{
try
{
string uri = string.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments", subscriptionId, cloudServiceName);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/xml";
request.Headers.Add("x-ms-version", "2013-03-01");
request.ClientCertificates.Add(cert);
string requestPayload = #"<Deployment xmlns=""http://schemas.microsoft.com/windowsazure"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<Name>[SomeName]</Name>
<DeploymentSlot>Production</DeploymentSlot>
<Label>[SomeLabel]</Label>
<RoleList>
<Role i:type=""PersistentVMRole"">
<RoleName>MyTestRole</RoleName>
<OsVersion i:nil=""true""/>
<RoleType>PersistentVMRole</RoleType>
<ConfigurationSets>
<ConfigurationSet i:type=""WindowsProvisioningConfigurationSet"">
<ConfigurationSetType>WindowsProvisioningConfiguration</ConfigurationSetType>
<ComputerName>[ComputerName]</ComputerName>
<AdminPassword>[AdminPassword - Ensure it's strong Password]</AdminPassword>
<AdminUsername>[Admin Username]</AdminUsername>
<EnableAutomaticUpdates>true</EnableAutomaticUpdates>
<ResetPasswordOnFirstLogon>false</ResetPasswordOnFirstLogon>
</ConfigurationSet>
<ConfigurationSet i:type=""NetworkConfigurationSet"">
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>3389</LocalPort>
<Name>RemoteDesktop</Name>
<Protocol>tcp</Protocol>
</InputEndpoint>
</InputEndpoints>
</ConfigurationSet>
</ConfigurationSets>
<DataVirtualHardDisks/>
<Label></Label>
<OSVirtualHardDisk>
<MediaLink>https://[storageaccount].blob.core.windows.net/vhds/fb83b3509582419d99629ce476bcb5c8__Microsoft-SQL-Server-2012SP1-Web-CY13SU04-SQL11-SP1-CU3-11.0.3350.0.vhd</MediaLink>
<SourceImageName>fb83b3509582419d99629ce476bcb5c8__Microsoft-SQL-Server-2012SP1-Web-CY13SU04-SQL11-SP1-CU3-11.0.3350.0</SourceImageName>
</OSVirtualHardDisk>
</Role>
</RoleList>
</Deployment>";
byte[] content = Encoding.UTF8.GetBytes(requestPayload);
request.ContentLength = content.Length;
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(content, 0, content.Length);
}
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
}
}
catch (WebException webEx)
{
using (var streamReader = new StreamReader(webEx.Response.GetResponseStream()))
{
string result = streamReader.ReadToEnd();
Console.WriteLine(result);
}
}
}
Hope this helps!
I have an Adobe Air 2.0 application that is also utilizing Spring BlazeDS integration. Inside this application I have a couple of data grids. The design was for each grid's model to register a Consumer to listen for changes pushed from BlazeDS. The first grid instantiated works correctly, however each subsequent grid causes the following warning in BlazeDS
[WARN] [Endpoint.StreamingAMF] Endpoint with id 'streaming-amf' received a duplicate streaming connection request from, FlexClient with id ''
I was under the impression you could have multiple consumers inside a Flex/Air application. Am I mistaken or have I just missed something in my configuration?
Server side channel definition
<channel-definition id="streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
<properties>
<add-no-cache-headers>false</add-no-cache-headers>
<max-streaming-clients>15</max-streaming-clients>
<user-agent-settings>
<user-agent match-on="AdobeAIR" kickstart-bytes="2048" max-streaming-connections-per-session="2" />
<user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="3" />
<user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="3" />
</user-agent-settings>
</properties>
</channel-definition>
Code for Channelset
<s:ChannelSet id="pricingCS">
<s:channels>
<s:StreamingAMFChannel id="streaming-amf"
url="http://localhost:8080/blazeds/messagebroker/streamingamf"
connectTimeout="5"/>
</s:channels>
</s:ChannelSet>
Code for Consumer
consumer = new Consumer();
consumer.id = "pricingConsumer";
consumer.destination = "pricingUpdates";
consumer.subtopic = pId;
consumer.channelSet = channelSet;
consumer.addEventListener(MessageEvent.MESSAGE, priceUpdate);
consumer.addEventListener(MessageFaultEvent.FAULT, priceUpdateFail);
consumer.subscribe();
I'm working on using the .Net SDK to help automate the deployment of an application into Windows EC2 instances. The process I want to achieve is:
Create a new EC2 instance - this
"bootstraps" itself by loading in
the new application version using a
service.
Ensure the new instance is in the
'running' state
Run some simple acceptance tests on
the new instance.
Register the new instance with an
existing Elastic Load balancer that
has an instance running the old
version of the application.
When the new instance is registered
with the load balancer, de-register
the old instance.
Stop the old EC2 instance.
I've managed to get steps 1 and 2 working, and I'm pretty confident about 3 and 6.
To do this I've been writing a simple C# console app that uses the AWS .Net SDK v1.3.2 to make the various API calls.
However, when I get to step 4 I cannot get the new instance registered with the load balancer. Here is my code:
public IList<Instance> PointToNewInstance(string newInstanceId)
{
var allInstances = new List<Instance>();
using (var elbClient = ClientUtilities.GetElbClient())
{
try
{
var newInstances = new List<Instance> {new Instance(newInstanceId)};
var registInstancesRequest = new RegisterInstancesWithLoadBalancerRequest
{
LoadBalancerName = LoadBalancerName,
Instances = newInstances
};
var registerReponse = elbClient.RegisterInstancesWithLoadBalancer(registInstancesRequest);
allInstances = registerReponse.RegisterInstancesWithLoadBalancerResult.Instances;
var describeInstanceHealthRequest = new DescribeInstanceHealthRequest
{
Instances = newInstances
};
DescribeInstanceHealthResponse describeInstanceHealthResponse;
do
{
describeInstanceHealthResponse = elbClient.DescribeInstanceHealth(describeInstanceHealthRequest);
} while (describeInstanceHealthResponse.DescribeInstanceHealthResult.InstanceStates[0].State == "OutOfService");
_log.DebugFormat("New instance [{0}] now in service - about to stop remove old instance", newInstanceId);
if (allInstances.Any(i => i.InstanceId != newInstanceId))
{
elbClient.DeregisterInstancesFromLoadBalancer(new DeregisterInstancesFromLoadBalancerRequest
{
Instances = allInstances.Where(i => i.InstanceId != newInstanceId).ToList(),
LoadBalancerName = LoadBalancerName
});
foreach (var instance in allInstances.Where(i => i.InstanceId != newInstanceId).ToList())
{
_log.DebugFormat("Instance [{0}] has now been de-registered from load-balancer [{1}]", instance.InstanceId, LoadBalancerName);
}
}
}
catch (Exception exception)
{
_log.Error(exception);
}
}
return allInstances.Where(i => i.InstanceId != newInstanceId).ToList();
}
The code just freezes at this line:
var registerReponse = elbClient.RegisterInstancesWithLoadBalancer(registInstancesRequest);
When I looked in more detail at the documention (relevant documentation here) I noticed this line:
NOTE: In order for this call to be
successful, the client must have
created the LoadBalancer. The client
must provide the same account
credentials as those that were used to
create the LoadBalancer.
Is it actually possible to use the API to register new instances with an existing load balancer?
All of that is easy to implement. Use Auto Scaling. Use API.
As Roman mentions, it sounds like Auto Scaling is a good way for you to go, it may not solve all of your problems but its certainly a good starting point:
-an auto scaling group can be tied to a load balancer, e.g. ill have x healthy instances
-new instances are automatically added to the load balancer (no traffic will be sent until it passed the health check)
-you can define custom health checks, such as ping http://hostname/isalive just have your instance respond to these requests once its passes step 3
-you can define scaling policies but by default if you're over capacity the oldest instances will be killed
-you don't mention the use case of the app but if you don't want a public facing address you can use an internal load balancer that doesn't take any traffic, just looks after the health check
-where possible you should always use least privilege principles for security, with your method you're going to have to give every instance a lot of power to control other instances, whether through mistake or abuse this can go wrong very easily
It seems that HttpWebRequest caching in WP7 is enabled by default, how do I turn it off?
Adding a random
param url + "?param=" + RND.Next(10000) works, but it's quite tricky and I'm not sure if it will work
with all servers.
For future reference , this worked for me ( I could not use additional query parameter due to project requirements) :
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
if (request.Headers == null)
{
request.Headers = new WebHeaderCollection();
}
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString();
In case of HttpClient (Portable for Windows Phone) "Cache-Control": "no-cache" on server side works only sometimes. And I cannot add query string random value to RESTful api call as well.
Solution from #frno works good and looks like for HttpClient:
client.DefaultRequestHeaders.IfModifiedSince = DateTime.UtcNow;
Thank you.
How do you know it's the phone, not the server (or a proxy somewhere between) which is caching?
Have you checked this with Fiddler2 (or equivalent)?
Have you tried setting headers to disable caching?
Something like:
myRequest = (HttpWebRequest)WebRequest.Create(myUri);
myRequest.Headers["Cache-Control"] = "no-cache";
myRequest.Headers["Pragma"] = "no-cache";
We've seen the same behaviour with Silverlight hosted in Chrome.
We add a "?nocache=" + DateTime.Now.Ticks.ToString() to our request URLs if we want to prevent caching.
I found 3 ways
Add a random Query String to the end of your URI (think Guid.NewGuid()) this will avoid caching on the client as the Query String will be different each time
string uri = "http://host.com/path?cache="+Guid.NewGuid().ToString();
Specify no cache in the OutgoingResponse header within your WCF service operation:
var __request = (HttpWebRequest)WebRequest.Create(url.ToString());
if (__request.Headers == null)
__request.Headers = new WebHeaderCollection();
__request.Headers.Add("Cache-Control", "no-cache");
markup your service operation with the AspNetCacheProfile attribute:
[AspNetCacheProfile("GetContent")]
public ResultABC GetContent(string abc)
{
__request = (HttpWebRequest)WebRequest.Create(abc);
return __request;
}
And update your web.config
<system.web>
<caching>
<outputCache enableOutputCache="true" />
<outputCacheSettings>
<outputCacheProfiles >
<add name="GetContent" duration="0" noStore="true" location="Client" varyByParam="" enabled="true"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
...
</system.web>
Adding random number is not bad and it will work. I have used Time (in ajax call). Was placed in the url like a folder.
Yes is possible... :) I spend one week of Experiment and the answer is really simple :
HttpWebRequest _webRequest = WebRequest.CreateHttp(_currentUrl);
_webRequest.AllowReadStreamBuffering = false
_webRequest.BeginGetResponse(_onDownload,
userState);