Solidity try catch to detect an address type - try-catch

I am not sure to understand the try / catch in solidity. The following code in intentionally wrong and the error should be caught, right?
function GetTest() external view returns (string memory) {
address _token_addr = 0x0000000000000000000000000000000000000000;
console.log("here");
ERC721 candidateContract = ERC721(_token_addr);
try candidateContract.supportsInterface(0x80ac58cd) {
console.log("try");
}
catch
{
console.log("catch");
}
return "";
}
What is the way to catch an error and check if the address has the expected type (token, address, contract) ?

The try/catch statement allows you to react on failed external calls
and contract creation calls
When you call candidateContract.supportsInterface(0x80ac58cd) if this function reverts, you will catch the error. For example, if you deploy those testCatch and ERC165 contracts
contract testCatch{
function GetTest() public view returns (string memory) {
// this is the address of deployed ERC165 contract down below
address _token_addr = 0x406AB5033423Dcb6391Ac9eEEad73294FA82Cfbc;
ERC165 candidateContract = ERC165(_token_addr);
try candidateContract.supportsInterface(0x80ac58cd) {
return "tried";
}
catch
{
return "catch";
}
}
}
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// this contract originally was abstract but I removed it to be able to deploy
contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// this require will fail
require(2==3,"wrong calculation");
return interfaceId == type(IERC165).interfaceId;
}
}
when you call the GetTest() function, it will revert because of require(2==3,"wrong calculation") line
However, if you removed the require line from ERC165 contract,
contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
And if you change this bytes4 "0x80ac58cd" to a wrong bytes4 "0x80ac5ccc", if you call the function, catch will not CATCH it. because supportsInterface function will not revert anything. So the code inside try block will run

Related

Cannot access a disposed context instance on GetQueryableAsync

For some reason when I call
GetQueryableAsync I get the error
ObjectDisposedException: Cannot access a disposed context instance.
But in the same class, if I call GetListAsync - it works fine - under the hood it looks like both methods are called GetDbContextAsync from the UnitOfWorkDbContextProvider
Can't figure out why one would work and the other doesn't
I really don't want to use the unit of work at all, so I have this
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
});
My code is like this
MyAppService : ApplicationService
{
public virtual IEnumerable<Setting> LoadByKey(string key)
{
//this works
return _repo.GetListAsync(x => x.Key.ToUpper() == key.ToUpper()).Result;
}
public IQueryable<Setting> GetAll()
{
// doesn't work, disposed context error
return _repo.GetQueryableAsync().Result;
}
}

Angular 2 - undefinded when sharing variable with API data between component

Basically what i try to do is to hit my API once and save the result inside global variable in my Service, and then share and modify this value in my parent and child component with two helpers functions.
repairs.service.ts
public myItems:any[];
public GetRepairs = ():Observable<any> => {
this.headers = new Headers();
this.headers.set('Authorization', 'Bearer' + ' ' + JSON.parse(window.localStorage.getItem('token')));
return this._http.get(this.actionUrl +'repairs'{headers:this.headers})
.map((res) => {return res.json();
}).map((item) => {
let result:Array<any> = [];
if (item.items) {
item.items.forEach((item) => {
result.push(item);
});
}
this.myItems = result;
return this.myItems;
});
};
public GetItems() {
return this.myItems;
};
public UpdateItems(data:any[]) {
this.myItems = data;
};
And then in my main component i do
repairs.component.ts
export class RepairsComponent implements OnInit {
public myItems:any[];
constructor(private _userService:UserService,
private _RepairsService:RepairsService,
public _GlobalService:GlobalService) {
}
ngOnInit() {
this._userService.userAuthenticate();
this.getAllItems();
}
private getAllItems():void {
this._RepairsService
.GetRepairs()
.subscribe((data) => {
this._RepairsService.UpdateItems(data);
},
error => console.log(error),
() => {
this.myItems = this._RepairsService.GetItems();
});
}
}
This work just fine but when i try to invoke GetItems() in child component i get undefinded. I try to do it inside constructor and ngOnInit with the same result.
child.component.ts
export class ChildComponent {
private items:any[] = [];
constructor(private _RepairsService:RepairsService,
private _Configuration:Configuration) {
this.items = this._RepairsService.GetItems();
// undefinded
}
ngOnInit() {
this.items = this._RepairsService.GetItems();
// undefinded
}
}
From what i can see in the limited amount of code you shared, it would seem you are trying to get the items before the http get call finishes and saves the data. I think a better design pattern would be to make the GetItems() function also an observable or promise, and check if the data is there, if not call the http get call, and once that completes send the data back to the different components that need it.
As #MSwehli mentioned with async code execution you can't rely on the order of code lines. In this code:
ngOnInit() {
this.items = this._RepairsService.GetItems();
// undefinded
}
the async code in GetItems(); is scheduled for later execution into the event queue and then continued with the sync code. The scheduled code will be executed eventually but it's not determined when. It depends on the response of the server in this example.
If you return a Promise you can use .then(...) the chain the execution so that your code is only executed when the async execution is completed.
There are two errors/inconsistencies in your code:
userAuthenticate() call followed with getAllItems() call. These calls are async, user is not yet authenticated by the time getAllItems() is called, getAllItems will fail.
Solution here is to chain calls using rxjs flatMap:
//assuming userAuthenticate returns Observable
userService.userAuthenticate().flatMap(()=>{
return repairsService.GetRepairs();
}).subscribe(..process repairs..);
getAllItems() is called nearly at the same time as GetItems(). In most cases it fails also, because previous http request is not completed when GetItems() is called.
In my opinion early initialization is not necessary here, use service directly:
//ChildComponent
ngOnInit() {
this._RepairsService.GetRepairs().subscribe(..do anything with list of repairs i.e. assign to bindable property..);
}
You could add console.log statements in each part of the code to see the order of events in your app.

Invoking a Multi-Threaded DLL at Run-Time

All, I call a .NET DLL containing a WinForm at run-time from a WinForm C# application. To do this I use the following:
DLL = Assembly.LoadFrom(strDllPath);
classType = DLL.GetType(String.Format("{0}.{1}", strNamespaceName, strClassName));
if (classType != null)
{
if (bDllIsWinForm)
{
classInst = Activator.CreateInstance(classType);
Form dllWinForm = (Form)classInst;
dllWinForm.Show();
// Invoke required method.
MethodInfo methodInfo = classType.GetMethod(strMethodName);
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(classInst, new object[] { dllParams });
return result == null ? String.Empty : result.ToString();
}
}
}
This is invoking the WinForm DLL and the required method fine for serial methods within the DLL. However, I am now invoking a multi-threaded DLL, and calling the following method:
public async void ExecuteTest(object[] args)
{
Result result = new Result();
if (!BuildParameterObjects(args[0].ToString(), args[1].ToString()))
return;
IProgress<ProgressInfo> progressIndicator = new Progress<ProgressInfo>(ReportProgress);
List<Enum> enumList = new List<Enum>()
{
Method.TestSqlConnection,
Method.ImportReferenceTables
};
Task task = Task.Factory.StartNew(() =>
{
foreach (Method method in enumList)
{
result = Process.ProcessStrategyFactory.Execute(Parameters.Instance, progressIndicator,
Process.ProcessStrategyFactory.GetProcessType(method));
if (!result.Succeeded)
{
// Display error.
return;
}
}
});
await task;
Utilities.InfoMsg("VCDC run executed successfully.");
}
But this is returning control to the caller right away due to the await (which is expected). However, the return causes the calling method to exit which closes the DLL WinForm.
What is the best method to keep the DLL WinForm active/open?
Thanks for your time.
Edit. Following the suggestion by Stephen below I have decided to turn my DLL intery method type to Task<object> and set up a continuation as follows
if (classType != null)
{
if (bDllIsWinForm)
{
// To pass object array to constructor use the following.
// classInst = Activator.CreateInstance(classType, new object[] {dllParams});
classInst = Activator.CreateInstance(classType);
dllWinForm = (Form)classInst;
dllWinForm.Show();
// Invoke required method.
MethodInfo methodInfo = classType.GetMethod(strMethodName);
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(classInst, new object[] { dllParams });
if (result != null)
{
if (result.GetType() == typeof(Task<object>))
{
Task<object> task = (Task<object>)result;
task.ContinueWith(ant =>
{
object innerResult = task.Result;
return innerResult == null ? String.Empty : innerResult.ToString();
});
}
return result.ToString();
}
return String.Empty;
}
}
}
I decided to set up the continuation instead of the await to avoid the chaining that would occur with the await keyword - that is making the calling method (that calling the DLL of type Task<String> etc. up the call stack.
The DLL entry method now becomes:
public Task<object> ExecuteTest(object[] args)
{
Task<object> task = null;
Result result = new Result();
if (!BuildParameterObjects(args[0].ToString(), args[1].ToString()))
return task;
IProgress<ProgressInfo> progressIndicator = new Progress<ProgressInfo>(ReportProgress);
List<Enum> enumList = new List<Enum>()
{
Method.TestSqlConnection,
Method.ImportReferenceTables
};
task = Task.Factory.StartNew<object>(() =>
{
foreach (Method method in enumList)
{
result = Process.ProcessStrategyFactory.Execute(Parameters.Instance, progressIndicator,
Process.ProcessStrategyFactory.GetProcessType(method));
if (!result.Succeeded)
{
// Display error.
}
task.Wait(5000); // Wait to prevent the method returning too quickly for testing only.
}
return null;
});
return task;
}
But this causes the DLL WinForm to be show for a split second and then disapear. i even attempted to make the Form dllWinForm global to keep the refernce to the object active, but this also has not worked. I want to note that the call to the DLL (N.B. the calling method is already running on a background thread-pool thread).
Any further helps is appreciated.
Change the return type of Execute to Task and await it.
It's difficult to guess what you have in dll but eventually your dll code + exposed in your question:
dllWinForm.Show();
should eventually have been after juxtaposing:
new Thread
(
() => new Form().ShowDialog()
)
.Start();
Probably, you should change dllWinForm.Show(); by dllWinForm.ShowDialog().Start();
ShowDialog(), in contrast with Show(), starts its own message pumping and returns only when explicitly closed.
Update (in respnse to comment):
It is not absolutely necessary to launch a form from UI.
Since you are on .NET 4.5, it is probably simpler to use WPF (instead of Windows Form) form.
Here is the code for WPF form which, in order to adjust for Windows Form, you should change Dispatcher parts by initializing WindowsFormsSynchronizationContext
Though, IMO, WinForms code will be much more complex.

Surviving TPL, Delegates, Threads, and Invokes

I'm facing a serious problem of deadlock in a multithreaded desktop/windows application. I fear I'm not using the correct approach to delegates in a very async environment. Also, even though I "sink" my events into the calling UI thread, if possible, I still have to Invoke on the UI thread to see some action. Follows, is the details.
The application is basically a client for users of an online file storage service. That service exposes functionality through REST calls. I first created a managed code wrapper DLL for such calls that allows for a .NET consumer to create a static instance of this DLL and call the functions. I'll take the file upload operation as an example.
Now, in the wrapper, here is the public interface for a file upload:
public Int32 UploadFile(FileSystemObject FolderToUploadTo, FileInfo LocalFileAndPath, OperationProgressReportEventHandler onOperationProgressReport, FileSystemObjectUploadCompletedEventHandler onOperationCompleted) {
Int32 ReplyNumber = 0;
try {
var TheOperation = new UploadFileObjectOperation(FolderToUploadTo, LocalFileAndPath, _User.APIKey) {
onProgressReport = onOperationProgressReport,
onUploadCompleted = onOperationCompleted
};
//Add it to the pool of operations
OperationPool.Add(TheOperation);
//Start the operation through the factory
OperationFactory.StartNew(() => {
TheOperation.Start();
});
//Chain the *actual* TPL Task to flush after usage
TheOperation.InnerTask.ContinueWith(t => {
t.Dispose(); //Dispose the inner task
OperationPool.Remove(TheOperation); //Remove the operation from the pool
TheOperation = null; //Nullify the Operation
});
ReplyNumber = TheOperation.TaskId;
}
catch {
ReplyNumber = 0;
}
return ReplyNumber;
}
As you can see, the actual UI application, that will refer this DLL, will be sending delegates for progress and completed to the operation(s). Now, the body of the operation itself:
public class UploadFileObjectOperation : BaseOperation, IDisposable {
//Store
public FileSystemObjectUploadCompletedEventHandler onUploadCompleted;
//Constructors
//Disposing stuff
protected override void PerformWork() {
try {
//Init the WebClient
UploadClient.UploadProgressChanged += (UploadProgressChanged_s, UploadProgressChanged_e) => {
//This is my event in base class being raised
ReportProgress(UploadProgressChanged_e.ProgressPercentage, UploadProgressChanged_e);
};
UploadClient.UploadFileCompleted += (UploadFileCompleted_s, UploadFileCompleted_e) => {
if (UploadFileCompleted_e.Error != null) {
throw new ApplicationException("Upload failed. " + UploadFileCompleted_e.Error.Message);
}
JObject JSONLiveObject = JObject.Parse(Encoding.UTF8.GetString(UploadFileCompleted_e.Result));
if (String.Compare((String)JSONLiveObject["status"], Constants._CONST_RESTRESPONSE_STATUS_VALUE_FAIL, false) == 0) {
throw new ApplicationException("Upload response failed. " + (String)JSONLiveObject["result"]["message"]);
}
//Eureka! Success! We have an upload!
//This is my event being raised
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = null,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Success,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
};
//Start the async upload
UploadClient.UploadFileAsync(AddressOfRESTURI, UploadingMethod, _FileToUpload.FullName);
}
catch (OperationCanceledException exp_Canceled) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp_Canceled,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Canceled,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// To ensure that the calling code knows the task was canceled
//throw;
}
catch (Exception exp) {
UploadTaskCompleted(new UploadFileObjectOperationEventArg {
Error = exp,
ResultSource = OperationResultSource.Fresh,
Status = OperationExitStatus.Error,
TaskId = TaskId,
UploadedFileSystemObject = _UploadedFile
});
// If the calling code also needs to know.
//throw;
}
}
protected void UploadTaskCompleted(UploadFileObjectOperationEventArg arg) {
if (onUploadCompleted == null)
return;
//Sinking into calling UI thread, if possible
if (onUploadCompleted.Target is Control) {
Control targetForm = onUploadCompleted.Target as Control;
targetForm.Invoke(onUploadCompleted, new object[] { arg });
}
else {
onUploadCompleted(arg);
}
Status = OperationRunningStatus.Completed;
}
}
The PerformWork() raises the two events: Progress reporting and completion. Note that while raising an event, I check if can get a route to the calling thread and push the event directly so to avoid invokes at UI.
Now, lets see how I'm using all of the above in a desktop client:
private void UploadFile(FileInfo DraggedFileInfo, FileSystemObject ParentDefination) {
SessionLifetimeStuff.APICore.UploadFile(ParentDefination, DraggedFileInfo,
(PercentageCompleted) => {
#region Progress
this.InvokeEx(f => {
UpdateTaskProgress(newTaskQueue.OID, PercentageCompleted.Progress, PercentageCompleted);
});
#endregion
}, (Result) => {
#region Completion
this.InvokeEx(f => {
switch (Result.Status) {
case OperationExitStatus.Success:
Console.WriteLine(String.Format("File: {0} uploaded to {1}", Result.UploadedFileSystemObject.DocumentFullname, Result.UploadedFileSystemObject.FolderId));
break;
case OperationExitStatus.Canceled:
DialogManager.ShowDialog(DialogTypeEnum.Warning, "Dropbox", "Upload canceled.", null, this);
break;
case OperationExitStatus.Error:
DialogManager.ShowDialog(DialogTypeEnum.Error, "Dropbox", "Upload failed.", Result.Error, this);
break;
}
});
#endregion
});
}
I'm using an extension method I found on Stackoverflow for adding the Invoking functionality:
public static class InvokeExtensions {
public static void InvokeEx<T>(this T #this, Action<T> action) where T : Control {
if (#this.InvokeRequired) {
#this.Invoke(action, new object[] { #this });
}
else {
if (!#this.IsHandleCreated)
return;
if (#this.IsDisposed)
throw new ObjectDisposedException("#this is disposed.");
action(#this);
}
}
public static IAsyncResult BeginInvokeEx<T>(this T #this, Action<T> action)
where T : Control {
return #this.BeginInvoke((Action)(() => #this.InvokeEx(action)));
}
public static void EndInvokeEx<T>(this T #this, IAsyncResult result)
where T : Control {
#this.EndInvoke(result);
}
}
In my code, i have commented out the invokes as I though i don't need then as the events being raised are coming in sinked. However, i realized that my UI was not doing anything at all. So, I added the InvokeEx({ code; }) and my UI started to shoe activity.
Now, why do I need to invoke?
If I attempt different operations from UI, eventually, my UI freezes although the application still behaves as normally functioning.
I found an old article at http://msdn.microsoft.com/en-us/library/ff649143.aspx#scag-ch06_topic4 that described the usage of delegates and I see that there is a IAsyncResult involved.
Could someone point me as to where I'm going wrong here?
Update:
Ok, with the invoking code commented on the UI, I get no activity at all. But upon using the this.InvokeEx or wrapping a work in this.BeginInvokeEx, I get UI updates but after a while, here are the two exceptions occurring (in this order):
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

Using Rx to simplify an asynchronous Silverlight web service request

I have written a simplified Silverlight client library for my WCF web service using Rx, however I notice sometimes I'm missing completed events.
public IObservable<XElement> GetReport(string reportName)
{
return from client in Observable.Return(new WebServiceClient())
from request in Observable.ToAsync<string>(client.GetReportDataAsync)(reportName)
from result in Observable.FromEvent<GetReportDataCompletedEventArgs>(client, "GetReportDataCompleted").Take(1)
from close in this.CloseClient(client)
select result.EventArgs.Result;
}
I believe the issue is caused by the fact that the web service is called and returns prior to subscribing to the completed event. I can't figure out how to get Rx to subscribe to the event prior to the Async call. I tried StartWith but that requires that the input and output types be the same, any ideas?
Seems like the best answer is to use Observable.CreateWithDisposable()
e.g.
public IObservable<XElement> GetReport(string reportName)
{
return from client in Observable.Return(new WebServiceClient())
from completed in Observable.CreateWithDisposable<GetReportDataCompletedEventArgs>(observer =>
{
var subscription = Observable.FromEvent<GetReportDataCompletedEventArgs>(client, "GetReportDataCompleted")
.Take(1)
.Select(e => e.EventArgs)
.Subscribe(observer);
client.GetReportDataAsync(reportName);
return subscription;
})
from close in this.CloseClient(client)
select completed.Result;
}
To make this easier to work with I refactored the CreateWithDisposable into a common function that can be used with all my web service calls, including automatically determining the event name from the event args type:
private IObservable<T> CallService<T>(ICommunicationObject serviceClient, Action start) where T : AsyncCompletedEventArgs
{
if (typeof(T) == typeof(AsyncCompletedEventArgs))
{
throw new InvalidOperationException("Event arguments type cannot be used to determine event name, use event name overload instead.");
}
string completedEventName = typeof(T).Name.TrimEnd("EventArgs");
return CallService<T>(serviceClient, start, completedEventName);
}
private IObservable<T> CallService<T>(ICommunicationObject serviceClient, Action start, string completedEventName) where T : AsyncCompletedEventArgs
{
return Observable.CreateWithDisposable<T>(observer =>
{
var subscription = Observable.FromEvent<T>(serviceClient, completedEventName).Take(1).Select(e => e.EventArgs).Subscribe(observer);
start();
return subscription;
});
}
// Example usage:
public IObservable<XElement> GetReport(string reportName)
{
return from client in Observable.Return(new WebServiceClient())
from completed in this.CallService<GetReportDataCompletedEventArgs>(client, () => client.GetReportDataAsync(reportName))
from close in this.CloseClient(client)
select completed.Result;
}
/// <summary>
/// Asynchronously closes the web service client
/// </summary>
/// <param name="client">The web service client to be closed.</param>
/// <returns>Returns a cold observable sequence of a single success Unit.</returns>
private IObservable<AsyncCompletedEventArgs> CloseClient(WebServiceClient client)
{
return this.CallService<AsyncCompletedEventArgs>(client, client.CloseAsync, "CloseCompleted");
}
Hope this helps someone else!
I need to use general WebClient.DownloadStringAsync so here my version.
First, wrap the event:
public static IObservable<IEvent<DownloadStringCompletedEventArgs>>
GetDownloadStringObservableEvent(this WebClient wc)
{
return Observable.FromEvent<DownloadStringCompletedEventArgs>(
wc, "DownloadStringCompleted");
}
Then create the extension method:
public static IObservable<string> GetDownloadString(this WebClient wc, Uri uri)
{
return Observable.CreateWithDisposable<string>(
observer => {
// Several downloads may be going on simultaneously. The token allows
// us to establish that we're retrieving the right one.
Guid token = Guid.NewGuid();
var stringDownloaded = wc.GetDownloadStringObservableEvent()
.Where(evt => ((Guid)evt.EventArgs.UserState) == token)
.Take(1); //implicitly unhooks handler after event is received
bool errorOccurred = false;
IDisposable unsubscribe =
stringDownloaded.Subscribe(
// OnNext action
ev => {
// Propagate the exception if one is reported.
if (ev.EventArgs.Error != null) {
errorOccurred = true;
observer.OnError(ev.EventArgs.Error);
} else if (!ev.EventArgs.Cancelled) {
observer.OnNext(ev.EventArgs.Result);
}
},
// OnError action (propagate exception)
ex => observer.OnError(ex),
// OnCompleted action
() => {
if (!errorOccurred) {
observer.OnCompleted();
}
});
try {
wc.DownloadStringAsync(uri, token);
} catch (Exception ex) {
observer.OnError(ex);
}
return unsubscribe;
}
);
}
Usage is simple:
wc.GetDownloadString(new Uri("http://myservice"))
.Subscribe(resultCallback , errorCallback);

Resources