I have created a WCF service and hosted it in IIS. I can access the WCF service by creating a web reference in my asp.net web forms application. I need to have the WCF web service run a long running method (async). Does anyone have good example code of how to call a WCF asynchronous method from an asp.net web forms application button click method?
I have looked at IAsyncResult, EAP, and TAP...
What currently is the best way to make an asynchronous call to a WCF asynchronous method from a ASP.NET web forms application?
I did now change my code to use a Service Reference instead of a Web reference.
Service ReceiptFooterService (ServiceContract, OperationsContract, DataContract):
using System.Collections.Generic;
using System.Net.NetworkInformation;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Threading.Tasks;
namespace ReceiptFooterDeploymentService
{
[ServiceContract]
public interface IReceiptFooterService
{
[OperationContract(Name = "GetRegisterPingResults")]
Task<List<PingReply>> GetRegisterPingResults(List<StoreIP> potentialIPs);
}
[DataContract]
public class StoreIP
{
private int _storeNumber;
private string _ipAddress;
[DataMember]
public int StoreNumber
{
get
{
return _storeNumber;
}
set
{
_storeNumber = value;
}
}
[DataMember]
public string IPAddress
{
get
{
return _ipAddress;
}
set
{
_ipAddress = value;
}
}
}
}
ReceiptFooterService class:
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
namespace ReceiptFooterDeploymentService
{
public class ReceiptFooterService : IReceiptFooterService
{
public async Task<List<PingReply>> GetRegisterPingResults(List<StoreIP> potentialIPs)
{
var tasks = potentialIPs.Select(sip => new Ping().SendPingAsync(sip.IPAddress, 1000));
var results = await Task.WhenAll(tasks);
return results.ToList();
}
}
}
ASP.NET web forms client: Only first few lines of the method (for brevity)
private List<StoreDetail> PingStoreAndUpdateStatus(List<StoreDetail> storeDetails)
{
ReceiptFooterService.StoreIP[] potentialIPs = GetStoreRegisterIps(storeDetails).ToArray();
ReceiptFooterService.ReceiptFooterServiceClient client = new ReceiptFooterService.ReceiptFooterServiceClient();
List<PingReply> pingReplies = client.GetRegisterPingResultsAsync(potentialIPs).Result.ToList();
I am attempting to ping approximately 2000 IP addresses asynchronously. I am getting back four results that show success. Although, none of the other PingReply details are showing. I need to know what IP address was pinged.
Should I be awaiting somewhere... is that why it is returning to soon, or is there an error causing it to fail. Any suggestions would be appreciated.
Below, is a QuickWatch of my results:
First, when using WCF why don't you use service reference?
(Web vs Service reference)
Then, when using SOAP client, it automatically generates SOAP WCF client with each method with synchronous and asynchronous variant.
Then you just call this async method
MyServiceClient.DummyMethodAsync(someParameters...)
I found that using a WCF web service for the kind of asynchronous work I needed to do (was not working from in the web service).
I switched to creating a console application that I call with arguments, and then store the results in a database. I then have the web site access the results stored in the database.
The console application context is much more friendly to completing the amount of asynchronous methods that I wanted to run at the same time.
Related
I have a simple webjob hosted on azure as a continuously running job.
I need to pass token value as a input , how can I achieve this using continuous web job?
static void Main(string[] args)
{
try
{
Console.WriteLine("Goto Login url" + kite.GetLoginURL());
Console.WriteLine("Enter request token: ");
string requestToken = Console.ReadLine();
I don't think it's possible using webjobs (continuos job) unless you have some web server running where you can fire requests against (e.g. sinatra, aspnet core, etc). You need to use Azure Functions with HTTP Trigger. Then you can pass the token in the querystring or in the body of the request and do what you need to do.
Webjob is background service, so you can not take user input using Console.ReadLine() anyway. Since WebJob does not have HTTP trigger like Azure Function, I see the only alternate way to pass message/input to a WebJob is to make it event-driven like using a queue trigger and do processing on receiving the queue message. Refer this quick-start guide for details.
Below uses .net core 3.1 with web job sdk v3. For equivalent code with older sdk, refer this.
Queue triggered job:
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
namespace WebJobsSDKSample
{
public class Functions
{
public static void ProcessQueueMessage([QueueTrigger("queue")] string message, ILogger logger)
{
// do stuffs with message
logger.LogInformation(message);
}
}
}
Program.cs
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
namespace WebJobsSDKSample
{
public class Program
{
static async Task Main()
{
var builder = new HostBuilder();
builder.ConfigureWebJobs(b =>
{
b.AddAzureStorageCoreServices();
});
var host = builder.Build();
using (host)
{
await host.RunAsync();
}
}
}
}
You can also explore some old samples here.But these are using v1 SDK.
I Have Written firebase database insertion code in web service and declared the method in web service as asynchronous. Now I want to call that async method in my windows form application button click event.
This is What i have tried:
Code for web service:
namespace Webservice
{
public class FireService1 : System.Web.Services.WebService
{
[WebMethod]
public async Task Insert()
{
mainform = new Form1();
SetResponse response = await
client.SetTaskAsync("Employee/"+mainform.txt_EID.Text,
Data.Instance.InsertInfo());
StudentData student = response.ResultAs<StudentData>();
}
}
}
Code for WinForm Application:
namespace FirebaseCRUD
{
public partial class Form1 : Form
{
FireService1SoapClient obj = new FireService1SoapClient();
private void btn_insert_Click(object sender, EventArgs e)
{
await obj.Insert();
}
}
}
I Want Insert() method to be invoked into insert button click event.But i am not getting the name of method when i try to call,
Thanks in Advance.
It is a bad idea to use Task and async/await with legacy technology like System.Web.Services.WebService since it was designed before async/await was introduced. These WebServices doesn't work properly with it. I recommend you to look at Asp.Net Core or at least WCF instead of System.Web.Services.WebService. Also you need to make a decision where asynchrony will be(on client side, on server side or both).
But if it is not production code, probably FireService1SoapClient generated async methods in "old style" with BeginXXX and EndXXX prefixes and you need to call obj.BeginInsert without await keyword.
I have my WCF which only returns a Boolean, has the contract created and within the WCF tests everything works correctly. The problem arises when I create the client and it does not execute the methods asynchronously.
I need to know if there is a way for the methods to run asynchronously.
Is there a way to generate an asynchronous method with the SVCUtil that works?
This is my interface
[ServiceContract]
public interface IService1
{
[OperationContractAttribute]
bool booleanMethod ();
}
TestWCF.svc class
public class TestWCF: IService1
{
public bool BooleanMethod ()
{
return BooleanMethod();
}
}
After this I generate my class with the svcUtil statement in the Developer Command Prompt.
svcutil.exe http://MyTest//Service.svc?wsdl
The created file is placed in my Xamarin Project and it works correctly when I use my normal method, but when using the same method asynchronously it gives me an error.
bool Result = Test.BooleanMethod (); // Execute correct
bool ResultAsync = Test.BooleanMethodAsync (); // It does not execute correctly
Can someone help me with the client's asynchronous calls?
I am completely new to WCF and multithreading. So, I followed this tutorial to set up a selfhosted WCF service. After I right-clicked on the Interface "INews_Service", I clicked on "implement Interface". Then, VS creates a method named DoWork().
In the tutorial above, the DoWork() method is not needed (-> it is deleted). However, in my project, I would like to use this method to run a background worker thread/task.
In my project, the background worker is supposed to permanently load data from an external device and store it in the DataContract-class. The WCF Service, in turn, is supposed to simultaneously provide the instance of that DataContract-class to external WCF consumers.
In reference to the tutorial above, what is the best way to add a background worker method, which constantly changes the variables within an instance of the DataContract-class?
EDIT:
#Brian: Thank you very much! The following example shows the selfhosted service program from the tutuorial above. After I start the host, I would like to run an endless loop that constantly updates my DataContract-class. Can you make an example, how this can be done? I do not need any synchronization, such as SpinLock or Monitor?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCF_NewsService
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(News_Service));
host.Open();
Console.WriteLine("Host Open Sucessfully ...");
while (true)
{
//here I want to constantly update my DataContract-class TOInews
}
}
}
}
EDIT2:
Actually, my problem is that I don't know how to access my DataContract-object objtoinews, which is defined in another file (i.e. in NewsService, as in the tutorial). When I run something like objtoinews.ID = 1;, VS complains that objtoinews is not defined in the current context.
while (true)
{
if (host.State != CommunicationState.Opened)
{
throw new Exception("SynchronizationWS Service Host failed.");
break;
}
else
{
objtoinews.ID = 1;
objtoinews.Header = "blabla";
objtoinews.Body = "huhu";
}
}
You don't need to use DoWork in a WCF solution. Basically, the console program described in that tutoral will perform DoWork() when the Host.Open() is called. In other words, Host.Open() will do what you expect DoWork() will do.
The console acts as the executable, but all the work is done asynchronously/multi-threaded in the background by WCF service.
Booz, I'm not sure why you think you need to continously update your DataContract. I don't think you can, actually, while the program's running. If you're worried about people sending different data constructs to your WS host, maybe you need to abstract the structure so that (basically) your clients can send virtually anything.
In any event, here's the code I'm use to loop and check the status of my web service:
while (true) {
//broken connection case
if (wshost.State != CommunicationState.Opened) {
throw new Exception("Service Host failed.");
//dump from loop and throw error
break;
}
Threading.Thread.Sleep(1000); //sleep 1 second
}
Can someone tell my why when I have wcf contract:
[ServiceContract]
public interface IService1
{
[OperationContract]
string TestGetName();
}
and implementation
public string TestGetName()
{
return "Kasia";
}
When I try consume it in Console app I can do just that:
Service1Client client = new Service1Client();
Console.WriteLine((client.TestGetName()));
but in Silverlight I must use that way :
Service1Client clientTest = new Service1Client();
clientTest.TestGetNameCompleted += new EventHandler<TestGetNameCompletedEventArgs>(clientTest_TestGetNameCompleted);
clientTest.TestGetNameAsync();
void clientTest_TestGetNameCompleted(object sender, TestGetNameCompletedEventArgs e)
{
this.dataGridChild.DataContext = e.Result;
}
Why in SL I don't see this first short solution, but only this with Event handlers?
Or better... why in Console app I can choose synchro operation generation and in SL I must use Generate asynchronous operations... :/
A synchronous call would stop the Silverlight UI thread and possibly the executing environment, i.e. the browser. To prevent this, only asynchronous calls are allowed.
Of course this is something unusual at first, but in the long run it is actually helpful to decouple the view and service layer.
Silverlight does not support synchronous calls (which is what you're doing in your console app).
Update: http://forums.silverlight.net/forums/p/34531/104526.aspx "The main point is that it looks like synchronous behaviour was removed on account of not being supported by all browsers."