I have an ASMX web service that I need to utilise as part of a piece of work. I am calling this service via an ASPX page to create new entities on a 3rd party system. I have no access to the underlying code to that service, its simply to allow me to communicate with another system.
Im having trouble finding out if I am calling the service correctly and I wonder if anyone could offer some advice.
I have installed the ASMX page and that has given me a class 'ConfirmConnector' which I call the BeginProcessOperations method. I want to wait on that to return and then parse te results. The results should be in XML which I then step through to get the data I am after.
The trouble is that sometimes this process just dies on me, i.e. when I call my 'EndProcessOperations' method then nothing happens. I dont get an error, nothing - my code just dies and the method returns'
My calling code is:
private void sendConfirmRequest(XmlManipulator requestXML)
{
file.WriteLine("Sending CONFIRM Request!");
AsyncCallback callBack = new AsyncCallback(processConfirmXML); // assign the callback method for this call
IAsyncResult r = conn.BeginProcessOperations(requestXML, callBack, AsyncState);
System.Threading.WaitHandle[] waitHandle = { r.AsyncWaitHandle }; // set up a wait handle so that the process doesnt automatically return to the ASPX page
System.Threading.WaitHandle.WaitAll(waitHandle, -1);
}
My handler code is :
/*
* Process the response XML from the CONFIRM Connector
*/
private static void processConfirmXML(IAsyncResult result)
{
try
{
file.WriteLine("Received Response from CONFIRM!");
if(result == null)
{
file.WriteLine("RESPONSE is null!!");
}
if(conn == null)
{
file.WriteLine("conn is null!!");
}
file.WriteLine("Is Completed : " + result.IsCompleted);
XmlNode root = conn.EndProcessOperations(result);
file.WriteLine("got return XML");
//writeXMLToFile("C:/response.xml",root.InnerXml);
file.WriteLine(root.InnerXml);
Can anyone advise if I am handling this code in the correct way and does anyone have any idea why my code randomly bombs after this line in the handler :
XmlNode root = conn.EndProcessOperations(result);
Thanks for your help,
Paul
thanks for looking, but I solved my problem. The issue appeared to be related to my callback operation.
I changed the code to call my begin & end methods in the same block of code and I havent had an issue since then.
private void sendConfirmRequest(XmlManipulator requestXML)
{
//ConfirmConnector conn = new ConfirmConnector();
file.WriteLine("Sending CONFIRM Request!");
//AsyncCallback callBack = new AsyncCallback(processConfirmXML); // assign the callback method for this call
//IAsyncResult r = conn.BeginProcessOperations(requestXML, callBack, AsyncState);
//System.Threading.WaitHandle[] waitHandle = { r.AsyncWaitHandle }; // set up a wait handle so that the process doesnt automatically return to the ASPX page
//System.Threading.WaitHandle.WaitAll(waitHandle, -1);
file.WriteLine("Calling BeginProcessOperations");
IAsyncResult result = conn.BeginProcessOperations(requestXML, null, null);
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
file.WriteLine("Calling EndProcessOperations");
XmlNode root = conn.EndProcessOperations(result);
processConfirmXML(root);
file.WriteLine("got return XML");
//writeXMLToFile("C:/response.xml",root.InnerXml);
file.WriteLine(root.InnerXml);
// Close the wait handle.
result.AsyncWaitHandle.Close();
}
Thanks
Paul
Related
The Situation
I'm working on a OAuth2 Api Wrapper. Some api routes are for logged people and some for anonymous and logged.
Here is an example of one method in my wrapper :
public async Task<UploadListResponse> List(bool pagination = false, int page = 1, int limit = 10)
{
var request = UploadRequests.List(pagination, page, limit);
var cancellationTokenSource = new CancellationTokenSource();
var restResponse = await Context.Client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
return restResponse.Handle<UploadListResponse>();
}
I build a request with all parameter set up then execute the request and then handle the answer in case I have an api error and then output an object containing all the data that request gave me.
The problem
With OAuth2, when you log to the API you'll receive an access token and a refresh token. If your access token is expired you have to contact the api with your refresh token to get a fresh new access token.
As I said earlier some of my method needs you to be logged but if your access token is expired I want to try to refresh token before throwing an exception like with this method :
public async Task<bool> NeedRelog()
{
try
{
var validAuth = await ValidAuth();
}
catch
{
try
{
var refresh = await Refresh(Context.Client.Config.RefreshToken);
}
catch
{
return true;
}
}
return false;
}
ValidAuth check with the API if you are logged and if I have an exception then I'll try to refreshToken.
I want to tag method that need logged to call NeedRelog() and those who aren't tag to not call it.
I may just do it in every method but it wouldn't be clean.
What I've done so far
I've found a great tool : PostSharp that seems to fit my needs.
I've started to do a checkLog aspect like this :
[Serializable]
public class CheckLog : OnMethodBoundaryAspect, IOnStateMachineBoundaryAspect
{
public CheckLog()
{
ApplyToStateMachine = false;
}
public override void OnEntry(MethodExecutionArgs args)
{
var instance = (ApiService)args.Instance;
var res = instance.Parent.OAuth.NeedRelog().Result;
if (!res)
{
args.Exception = new Exception("Need to relog");
args.FlowBehavior = FlowBehavior.Return;
}
}
}
Where I'm stuck
The Main problem is with the call to my NeedRelog() Method. Due to the fact this is an async method I'm struggling to make my aspect await for it.
If my OnEntry method is async then It won't block the call if you are not logged.
If my OnEntry method is not async and I wait for needLog it freeze and nothing happen.
I really want to know to use this kind of "conditional method call" with postsharp, it looks awesome but the fact is after looking for hours in the documentation I didn't find a way to do what I want.
I'm starting to ask myself if it is even possible to achieve what I'm aiming to do.
Did you try using a way to make the call synchronous maybe with something like this stackoverflow.com/a/25097498/3131696 ? – M22an 5 hours ago
As I can't mark a comment as answering a question I quote your comment to make this question answered as it is said here : link
Thanks you for this M22an.
public BarchartParser()
{
// Initialize list
StockSymbols = new List<string>();
// Add items
ParseBarchart();
}
this is the C'tor that calls the method
private async void ParseBarchart()
{
try
{
#region Get Html Document
// Get response from site
HttpClient http = new HttpClient();
var response = await http.GetByteArrayAsync(BARCHART_WEBSITE);
/* Break or W/e happens on this line ^^^ */
// Encode html response to UTF-8
string source = Encoding.GetEncoding(BARCHART_ENCODING)
.GetString(response, 0, response.Length - 1);
// Get html
HtmlDocument document = new HtmlDocument();
document.LoadHtml(source);
#endregion
#region Get Data From Table
// Get table containining stock info
HtmlNode table = document.DocumentNode.Descendants()
.Single<HtmlNode>
(
x => (x.Name == "table") &&
(x.Attributes["class"] != null) &&
(x.Attributes["class"].Value.Equals("datatable ajax")) &&
(x.Attributes["id"].Value.Equals("dt1"))
);
// Get 'tbody' element from table
HtmlNode tbody = table.Descendants("tbody").FirstOrDefault();
// Get all rows from the table
List<HtmlNode> allStocks = tbody.Descendants("tr").ToList();
// For each row, id is "td1_X" where X is the symbol of the stock
foreach (HtmlNode row in allStocks)
{
StockSymbols.Add(row.Attributes["id"].Value.ToString()
.Split(new char[] { '_' })[1]);
}
#endregion
}
catch
{
StockSymbols = new List<string>();
StockSymbols.Add("this didn't work");
}
}
And the code from a simple form application that uses this:
BarchartParser barchartData;
public Form1()
{
InitializeComponent();
barchartData = new BarchartParser();
}
private void Form1_Load(object sender, EventArgs e)
{
if (barchartData.StockSymbols != null && barchartData.StockSymbols.Count > 0)
MessageBox.Show(barchartData.StockSymbols[0]);
else
MessageBox.Show("barchartData.StockSymbols is null or count == 0");
this.Close();
}
Not exactly sure what's going on here. It worked for one time that I debugged and then it stopped working.
This code is part of a function that is called during a C'tor. When this throw or whatever happens,
It just continues to the next breakpoint that I set in debug mode... Anyone has a clue of what
May be the cause of this?
Edit: I know it's not a throw because the code in the catch block doesn't happen. It simply moves on
Just in general, i'm following this guide https://code.msdn.microsoft.com/Parsing-Html-using-C-721be358/sourcecode?fileId=122353&pathId=1834557721
You are not await-ing async method so only synchronous portion of the method (basically up to first real await) will be executed as part of your constructor call and the rest will eventually run on some arbitrary tread (possibly bringing process down in case of exception).
Generally you can't call async methods from constructor without good chance of deadlock if you try to call .Result or .Wait() (await vs Task.Wait - Deadlock?). As an option you can see if Fire-and-forget with async vs "old async delegate" works for your case.
Proper fix would be to move async operation from synchronous method (like constructor) to explicit async method and call it accordingly.
Hacky fix (with likley deadlock):
public BarchartParser()
{
...
ParseBarchart().Wait();
}
When an await statement throws an exception, only a try block can catch it. I suggest you add a try-catch or try-finally to catch the exception and handle it properly.
I hope I can word this correctly. I have a WCF Service that I'm using (duplex channel communications) in which one client registers with the service. The service's registration method returns a value. I want the the method of the called service registration method to also call the callback method that will send out notification of the client registration (I have my reasons for this and explaining it here will only confuse the issue). The problem is that the client's implemented callback has to run in the main application thread to work correctly (due mostly to integration with a third-party application). The service registration method call is also occuring in this same thread, so it effectively locks up since the client is looking for a return from the service registration method holding on to the thread preventing the callback method from being able to run. If I tell it to call all callback methods for all contexts other than the one just registered, it works just fine. But if I tell it to include it, obviously it locks up because that thread is already locked up. I can set the callback attribute property for UseSynchronizationContext to false, but then this means the callback method is called on a separate thread from the main and now the rest of the program will not work. Any help would be greatly appreciated.
Here's basically that registration method (first draft..)
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple,
Namespace = "http://MyApp/Design/CADServiceTypeLibrary/2012/12")]
public class DTOTransactionService : IDTOTransactionService, IDisposable
{
//some more stuff
public CADManager RegisterCADManager(int processID, bool subscribeToMessages)
{
List<CADManager> cadMgrs = this.CADManagers;
bool registered = false;
//Create new CADManager mapped to process id
CADManager regCADManager = new CADManager(processID);
//Add to CADManagers List and subscribe to messages
if (regCADManager.IsInitialized)
{
cadMgrs.Add(regCADManager);
this.CADManagers = cadMgrs;
//Subscribe to callbacks
if (subscribeToMessages)
SubscribeCallBack(regCADManager.ID);
registered = true;
}
//Send registration change notification
RegistrationState state;
if (registered)
state = RegistrationState.Registered;
else
state = RegistrationState.RegistrationException;
foreach (CallBackSubscriber subscriber in this.CallBackSubscribers)
{
subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state);
}
return regCADManager;
}
}
I think I've got it figured out. It struck me that a little deeper what's happening is that since the call to the service method is expecting a return value and since the callback will occur in the same thread as the client method expecting a return value that this could be the result of the deadlock condition. I then decided to try calling the callback methods in the service using a different thread to work around the current thread condition. In other words, work around the current thread whose method has yet to have provided a return value from the service method. It worked! Was this the right approach? I have enough experience to be dangerous here, so if someone else's experience shows this to be the wrong way to handle this, I'm all ears.
Thread notifyThread = new Thread(delegate()
{
foreach (CallBackSubscriber subscriber in this.CallBackSubscribers)
{
subscriber.CallBackProxy.CADManagerRegistrationNotification(regCADManager.ID, state);
}
});
Update:
Yes, the threading and deadlock condition was the issue, however the more appropriate fix I recently discovered is to use SynchronizationContext. To use, create a property or field of the type SynchronizationContext, then assign the value to the field/property while in the context you wish to capture using SynchronizationContext.Current. Then, use the Post() method (providing it a delegate via the SendOrPostCallback object) in the callback method being called by the Service. A short example:
private SynchronizationContext _appSyncContext = null;
private DTOCommunicationsService()
{
this.AppSyncContext = SynchronizationContext.Current;
//Sets up the service proxy, etc, etc
Open();
}
// Callback method
public void ClientSubscriptionNotification(string clientID, SubscriptionState subscriptionState)
{
SendOrPostCallback callback = delegate(object state)
{
object[] inputArgs = (object[])state;
string argClientID = (string)inputArgs[0];
SubscriptionState argSubState = (SubscriptionState)inputArgs[1];
//Do stuff with arguments
};
_appSyncContext.Post(callback, new object[] { clientID, subscriptionState });
}
I am using an asynchronous delegate that invokes a method which loads an xml file into an XPathDocument. If the xml is too big to fit into memory it never finishes loading. the code below works if the xml file is successfully loaded into the XPathDocument. I have been able to use a timer event that executes the asyncXpath.EndInvoke(result) statement and that works to end the CreateDocument method, but it does not stop the XPathDocument from loading. My conclusion is that the only thing I can do is to issue an Application.End statement to kill the application. Does anyone know how to stop a blackbox operation such as loading an XPathDocument.
delegate bool AsyncXpathQueryCaller(string xmlfile
bool found = false;
AsyncXpathQueryCaller asyncXpath = new
AsyncXpathQueryCaller(CreateDocument);
IAsyncResult result = asyncXpath.BeginInvoke(xmlfile, null, null);
while (!result.IsCompleted)
{
result.AsyncWaitHandle.WaitOne(100, false);
}
found = asyncXpath.EndInvoke(result);
private bool CreateDocument (string xmlfile)
{
XPathDocument doc = new XPathDocument(xmlfile);
}
What about using FileInfo before you try to load it and checking the size? If it's too big just skip it.
Something like this:
FileInfo fi = new FileInfo(xmlfile);
if(fi.Length < /*some huge number*/)
{
//load the file
}
You could declare a FileStream and give it to the constructor, but before you do, look at its Length property, and if it's too long, just return an error.
As proposed by Abe Miessler it is sensible to check the file size even before attempting to load it into an XPathDocument.
How would one decide what should be the limit?
There is no exact rule, but I have heard people say that you should multiply the file size by 5 and then the result is close to the memory that the XmlDocument will require in order for the text to be loaded/parsed.
EDIT: I just realized that KeithS has come close to a good answer. The basic idea is that you call the XPathDocument constructor that accepts a Stream which wraps a FileStream. The object you pass it should implement the Read(byte[], int, int) function to call the wrapped FileStream's Read function, or throw an exception if the operation has timed out. Here's a code sample:
class XmlStream : FileStream
{
DateTime deadline;
public XmlStream(string filename, TimeSpan timeout)
: base(filename, FileMode.Open)
{
deadline = DateTime.UtcNow + timeout;
}
public override int Read(byte[] array, int offset, int count)
{
if (DateTime.UtcNow > deadline)
throw new TimeoutException();
return base.Read(array, offset, count);
}
}
Here's some code that reads in document, but times out after 1 second:
bool found = true;
using(var stream = new XmlStream(document, TimeSpan.FromSeconds(1)))
try
{
xpath = new XPathDocument(stream);
}
catch (TimeoutException)
{
found = false;
}
If you create a separate thread instead of doing a BeginInvoke, you can just abort the thread when a timer ticks (or somebody clicks "Cancel"). While aborting threads is generally not advisable because it could be holding a lock or have global data in an inconsistent state, in this case it should be fine because your thread would not be holding a lock or accessing global data.
Here's the code for this method that does the same as the previous sample:
bool found = false;
thread = new Thread(() =>
{
xpath = new XPathDocument(document);
found = true;
});
thread.Start();
thread.Join(TimeSpan.FromSeconds(1));
thread.Abort();
If you're uncomfortable with aborting threads in your own app domain, you can create the document in another app domain and call AppDomain.Unload on it if it takes too long. That will require some marshalling, but probably won't have too much overhead.
The ultimate way to be able to kill a process is to run it in a separate process and use some sort of remoting interface to access it. That's probably even messier that the other options, though, as you have to worry about finding the executable, passing parameters, some user terminating it, and so on.
What's a callback and how is it implemented in C#?
I just met you,
And this is crazy,
But here's my number (delegate),
So if something happens (event),
Call me, maybe (callback)?
In computer programming, a callback is executable code that is passed as an argument to other code.
—Wikipedia: Callback (computer science)
C# has delegates for that purpose. They are heavily used with events, as an event can automatically invoke a number of attached delegates (event handlers).
A callback is a function that will be called when a process is done executing a specific task.
The usage of a callback is usually in asynchronous logic.
To create a callback in C#, you need to store a function address inside a variable. This is achieved using a delegate or the new lambda semantic Func or Action.
public delegate void WorkCompletedCallBack(string result);
public void DoWork(WorkCompletedCallBack callback)
{
callback("Hello world");
}
public void Test()
{
WorkCompletedCallBack callback = TestCallBack; // Notice that I am referencing a method without its parameter
DoWork(callback);
}
public void TestCallBack(string result)
{
Console.WriteLine(result);
}
In today C#, this could be done using lambda like:
public void DoWork(Action<string> callback)
{
callback("Hello world");
}
public void Test()
{
DoWork((result) => Console.WriteLine(result));
DoWork(Console.WriteLine); // This also works
}
Definition
A callback is executable code that
is passed as an argument to other code.
Implementation
// Parent can Read
public class Parent
{
public string Read(){ /*reads here*/ };
}
// Child need Info
public class Child
{
private string information;
// declare a Delegate
delegate string GetInfo();
// use an instance of the declared Delegate
public GetInfo GetMeInformation;
public void ObtainInfo()
{
// Child will use the Parent capabilities via the Delegate
information = GetMeInformation();
}
}
Usage
Parent Peter = new Parent();
Child Johny = new Child();
// Tell Johny from where to obtain info
Johny.GetMeInformation = Peter.Read;
Johny.ObtainInfo(); // here Johny 'asks' Peter to read
Links
more details for C#.
A callback is a function pointer that you pass in to another function. The function you are calling will 'callback' (execute) the other function when it has completed.
Check out this link.
If you referring to ASP.Net callbacks:
In the default model for ASP.NET Web
pages, the user interacts with a page
and clicks a button or performs some
other action that results in a
postback. The page and its controls
are re-created, the page code runs on
the server, and a new version of the
page is rendered to the browser.
However, in some situations, it is
useful to run server code from the
client without performing a postback.
If the client script in the page is
maintaining some state information
(for example, local variable values),
posting the page and getting a new
copy of it destroys that state.
Additionally, page postbacks introduce
processing overhead that can decrease
performance and force the user to wait
for the page to be processed and
re-created.
To avoid losing client state and not
incur the processing overhead of a
server roundtrip, you can code an
ASP.NET Web page so that it can
perform client callbacks. In a client
callback, a client-script function
sends a request to an ASP.NET Web
page. The Web page runs a modified
version of its normal life cycle. The
page is initiated and its controls and
other members are created, and then a
specially marked method is invoked.
The method performs the processing
that you have coded and then returns a
value to the browser that can be read
by another client script function.
Throughout this process, the page is
live in the browser.
Source: http://msdn.microsoft.com/en-us/library/ms178208.aspx
If you are referring to callbacks in code:
Callbacks are often delegates to methods that are called when the specific operation has completed or performs a sub-action. You'll often find them in asynchronous operations. It is a programming principle that you can find in almost every coding language.
More info here: http://msdn.microsoft.com/en-us/library/ms173172.aspx
Dedication to LightStriker:
Sample Code:
class CallBackExample
{
public delegate void MyNumber();
public static void CallMeBack()
{
Console.WriteLine("He/She is calling you. Pick your phone!:)");
Console.Read();
}
public static void MetYourCrush(MyNumber number)
{
int j;
Console.WriteLine("is she/he interested 0/1?:");
var i = Console.ReadLine();
if (int.TryParse(i, out j))
{
var interested = (j == 0) ? false : true;
if (interested)//event
{
//call his/her number
number();
}
else
{
Console.WriteLine("Nothing happened! :(");
Console.Read();
}
}
}
static void Main(string[] args)
{
MyNumber number = Program.CallMeBack;
Console.WriteLine("You have just met your crush and given your number");
MetYourCrush(number);
Console.Read();
Console.Read();
}
}
Code Explanation:
I created the code to implement the funny explanation provided by LightStriker in the above one of the replies. We are passing delegate (number) to a method (MetYourCrush). If the Interested (event) occurs in the method (MetYourCrush) then it will call the delegate (number) which was holding the reference of CallMeBack method. So, the CallMeBack method will be called. Basically, we are passing delegate to call the callback method.
Please let me know if you have any questions.
Probably not the dictionary definition, but a callback usually refers to a function, which is external to a particular object, being stored and then called upon a specific event.
An example might be when a UI button is created, it stores a reference to a function which performs an action. The action is handled by a different part of the code but when the button is pressed, the callback is called and this invokes the action to perform.
C#, rather than use the term 'callback' uses 'events' and 'delegates' and you can find out more about delegates here.
callback work steps:
1) we have to implement ICallbackEventHandler Interface
2) Register the client script :
String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context");
String callbackScript = "function UseCallBack(arg, context)" + "{ " + cbReference + ";}";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "UseCallBack", callbackScript, true);
1) from UI call Onclient click call javascript function for EX:- builpopup(p1,p2,p3...)
var finalfield= p1,p2,p3;
UseCallBack(finalfield, ""); data from the client passed to server side by using UseCallBack
2) public void RaiseCallbackEvent(string eventArgument) In eventArgument we get the passed data
//do some server side operation and passed to "callbackResult"
3) GetCallbackResult() // using this method data will be passed to client(ReceiveServerData() function) side
callbackResult
4) Get the data at client side:
ReceiveServerData(text) , in text server response , we wil get.
A callback is a function passed as an argument to another function. This technique allows a function to invoke the parameter function argument and even to pass a value back to the caller. A callback function can be designed to run before/after the function has finished and can pass a value.
It is a kind of construct where you call a long running function and ask him to call you back once it has finished with can return a parameter result to the caller.
It's like someone calls you in the middle of your work asking for status and you say "you know what give me 5 min and i will call you back" and at the end you call him to update. If you are a function the caller just added and passed another function that you invoked at the end. This can simpley be written in C# as:
public void VinodSrivastav(Action statusUpdate){
//i am still here working..working
//i have finished, calling you
statusUpdate();
}
//invokes
stackoverflow.VinodSrivastav((cam) => {
Console.Write("Is it finished");
});
The one simple example is the iterator function where the return will be multiple times, one can argue that we have yield for it:
public void IntreationLoop(int min, int max,Action<int> Callback)
{
for(int i = min;i<= max;i++)
Callback(i);
}
//call
IntreationLoop(5,50,(x) => { Console.Write(x); }); //will print 5-50 numbers
In the code above the function return type is void but it has an Action<int> callback which is called and sends each item from the loop to the caller.
The same thing can be done with if..else or try..catch block as:
public void TryCatch(Action tryFor,Action catchIt)
{
try{
tryFor();
}
catch(Exception ex)
{
Console.WriteLine($"[{ex.HResult}] {ex.Message}");
catchIt();
}
}
And call it as:
TryCatch(()=>{
int r = 44;
Console.WriteLine("Throwing Exception");
throw new Exception("something is wrong here");
}, ()=>{
Console.WriteLine("It was a mistake, will not try again");
});
In 2022 we have Func & Action doing the same, please see the demo code below which shows how this can be be used:
void Main()
{
var demo = new CallbackDemo();
demo.DoWork(()=> { Console.WriteLine("I have finished the work"); });
demo.DoWork((r)=> { Console.WriteLine($"I have finished the work here is the result {r}"); });
demo.DoWork(()=> { Console.WriteLine($"This is passed with func"); return 5;});
demo.DoWork((f)=> { Console.WriteLine($"This is passed with func and result is {f}"); return 10;});
}
// Define other methods and classes here
public class CallbackDemo
{
public void DoWork(Action actionNoParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
actionNoParameter(); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Action<int> actionWithParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
actionWithParameter(result); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Func<int> funcWithReturn)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
int c = funcWithReturn(); //execute
result += c;
Console.WriteLine($"[The Actual Result is {result}]");
}
public void DoWork(Func<int,int> funcWithParameter)
{
int a = 5;
int b = 10;
//i will do th maths and call you back
int result = a + b;
//callback
result += funcWithParameter(result); //execute
Console.WriteLine($"[The Actual Result is {result}]");
}
}