I've created a minimal reproduction here: https://github.com/mushishi78/transaction-minimal-reproduction
Essentially I've hit a NotImplementedException given by mono's TransactionInterop that seems to imply that it's not ready for async transactions. But as I'm not that experienced with .NET, I was hoping for some second opinions or advice.
Have I done something odd in the implementation and if I wrote it correctly this would be completely fine?
Should I wrestle with upgrading to a later version of Npgsql even though I had trouble with that originally?
Should I give up on async for the time being because it possible doesn't make as much difference in .NET world?
Should I give up on SQLProvider as other ORM/object mapper libraries don't have these issues (eg. Dapper)?
Would I have better luck not using Postgres as SQL Server is much better supported in .NET world?
Or is it mono that's just not ready for primetime and I'm better off making a server run on a windows box?
Code
open FSharp.Data.Sql
open System.Transactions
let [<Literal>] connectionString = "Host=localhost;Database=example;Username=postgres;Password=postgres;Enlist=true"
let [<Literal>] resolutionPath = __SOURCE_DIRECTORY__ + #"..\packages\Npgsql.3.1.0\lib\net451"
type sql = SqlDataProvider<Common.DatabaseProviderTypes.POSTGRESQL,
connectionString,
ResolutionPath = resolutionPath,
UseOptionTypes = true>
let withTransaction fn =
async {
use transaction = new TransactionScope (TransactionScopeAsyncFlowOption.Enabled)
let ctx = sql.GetDataContext ()
let! result = fn ctx
transaction.Complete ()
return result
}
let createPerson (ctx: sql.dataContext) =
let row = ctx.Public.Person.Create ()
row.Id <- 1
row.Name <- "Hello"
ctx.SubmitUpdatesAsync ()
let editPerson (ctx: sql.dataContext) =
query {
for row in ctx.Public.Person do
take 1
}
|> Seq.iter (fun row -> row.Name <- "Hi there!")
|> ctx.SubmitUpdatesAsync
let deletePerson (ctx: sql.dataContext) =
query {
for row in ctx.Public.Person do
take 1
}
|> Seq.iter (fun row -> row.Delete ())
|> ctx.SubmitUpdatesAsync
let run (ctx: sql.dataContext) =
async {
do! createPerson ctx
do! editPerson ctx
do! deletePerson ctx
}
[<EntryPoint>]
let main argv =
withTransaction run
|> Async.RunSynchronously
|> ignore
0
StackTrace
The method or operation is not implemented.
at System.Transactions.TransactionInterop.GetTransmitterPropagationToken (System.Transactions.Transaction transaction) [0x00000] in /Users/builder/jenkins/workspace/build-package-osx-mono/2019-06/external/bockbuild/builds/mono-x64/mcs/class/System.Transactions/System.Transactions/TransactionInterop.cs:57
at Npgsql.NpgsqlPromotableSinglePhaseNotification.Enlist (System.Transactions.Transaction tx) [0x00070] in <301d14fab821450fa5cc07ec7c940a17>:0
at Npgsql.NpgsqlConnection.OpenInternal () [0x0012c] in <301d14fab821450fa5cc07ec7c940a17>:0
at Npgsql.NpgsqlConnection.Open () [0x00000] in <301d14fab821450fa5cc07ec7c940a17>:0
at FSharp.Data.Sql.Common.Sql.connect[a] (System.Data.IDbConnection con, Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] f) [0x00009] in <5d776594de6dfdbfa74503839465775d>:0
at FSharp.Data.Sql.Providers.PostgresqlProvider.FSharp-Data-Sql-Common-ISqlProvider-GetColumns (System.Data.IDbConnection con, FSharp.Data.Sql.Schema.Table table) [0x000ae] in <5d776594de6dfdbfa74503839465775d>:0
at FSharp.Data.Sql.Runtime.SqlDataContext.FSharp-Data-Sql-Common-ISqlDataContext-CreateEntity (System.String tableName) [0x0001f] in <5d776594de6dfdbfa74503839465775d>:0
at Program.createPerson (System.Object ctx) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:22
at Program+run#45.Invoke (Microsoft.FSharp.Core.Unit unitVar) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:45
at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult] (Microsoft.FSharp.Control.AsyncActivation`1[T] ctxt, TResult result1, Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] part2) [0x00005] in <039b17603f7a807e0eeaa652dc64c784>:0
at Program+withTransaction#16-4[a].Invoke (Microsoft.FSharp.Control.AsyncActivation`1[T] ctxt) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:16
at Microsoft.FSharp.Control.Trampoline.Execute (Microsoft.FSharp.Core.FSharpFunc`2[T,TResult] firstAction) [0x00020] in <039b17603f7a807e0eeaa652dc64c784>:0
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.FSharp.Control.AsyncResult`1[T].Commit () [0x0002c] in <039b17603f7a807e0eeaa652dc64c784>:0
at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInCurrentThread[a] (System.Threading.CancellationToken cancellationToken, Microsoft.FSharp.Control.FSharpAsync`1[T] computation) [0x00028] in <039b17603f7a807e0eeaa652dc64c784>:0
at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T] (System.Threading.CancellationToken cancellationToken, Microsoft.FSharp.Control.FSharpAsync`1[T] computation, Microsoft.FSharp.Core.FSharpOption`1[T] timeout) [0x00013] in <039b17603f7a807e0eeaa652dc64c784>:0
at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T] (Microsoft.FSharp.Control.FSharpAsync`1[T] computation, Microsoft.FSharp.Core.FSharpOption`1[T] timeout, Microsoft.FSharp.Core.FSharpOption`1[T] cancellationToken) [0x0006e] in <039b17603f7a807e0eeaa652dc64c784>:0
at Program.main (System.String[] argv) [0x00000] in /Users/max/dev2/TransactionMinimalReproduction/TransactionMinimalReproduction/Program.fs:52
Any and all help would be appreciated.
Related
I'm using EF 6 and Z.EntityFramework.Extensions.
The following code:
using (var context = contextFactory())
{
var modified = context.Receita.
Where(r => r.V_UID == receitaEletronica.VendaUid && r.numeroreceita == receitaEletronica.NumeroReceita).
Join(context.Tabela_Comparticipacao.
Where(t => entidades.Contains(t.ec_uid)).
Join(context.Tabela_Comparticipacao.Where(t => t.flag_elect == 1),
source => source.ec_uid,
dest => dest.ec_uid,
(source, dest) => new { Source = source, Dest = dest }),
r => r.TaCo_UID,
t => t.Source.TaCo_UID,
(r, t) => new { Receita = r, NovoTaCo = t.Dest.TaCo_UID }).
UpdateFromQuery(r => new Receita { TaCo_UID = r.NovoTaCo });
}
throws the following exception:
Message:
Test method winphar.services.receitas.ReceitasDAOTest.TestAtualizarReceitaElectronicaTaCoUidEntidadesCentralizadas threw exception:
System.Exception: Oops! Invalid update expression, the body is not a NewExpression. Please refer to the documentation to get examples about how to use this feature.
Stack Trace:
DbContextExtensions.[](IQueryable`1 , Expression`1 , Action`1 , Boolean )
DbContextExtensions.UpdateFromQuery[TEntity](IQueryable`1 query, Expression`1 updateExpression, Action`1 bulkOperationFactory)
DbContextExtensions.UpdateFromQuery[TEntity](IQueryable`1 query, Expression`1 updateExpression)
ReceitasDAO.AtualizarReceitaElectronicaTaCoUidEntidadesCentralizadas(ReceitaEletronica receitaEletronica, List`1 entidades) line 114
ReceitasDAOTest.TestAtualizarReceitaElectronicaTaCoUidEntidadesCentralizadas() line 267
What am I doing wrong?
I have received such error when context had different object then the one I was passing to UpdateFromQuery.
For example for context DbSet<A> I accidentally put new B()
context.A.
Where(x => x.Id == id).
UpdateFromQuery(x => new B
{
Example = exampleId
});
Hope it helps!
I am using the Firebase Unity SDK for authentication with FB and Google.
When trying it out on iOS FB works fine, but whenever I login with Google it works the first time, but when I relaunch the application and try to use the Google login again it causes an internal Firebase error.
Here's the printout I get :
SignInWithCredentialAsync encountered an error: System.AggregateException: Exception of type 'System.AggregateException' was thrown.
-----------------
Encountered a FirebaseException:An internal error has occurred, print and inspect the error details for more information.
Valley.DatabaseHandler:<RequestLogin>m__0(Task`1)
System.Threading.Tasks.<ContinueWith>c__AnonStorey0:<>m__0(Task)
System.Threading.Tasks.<ContinueWith>c__AnonStorey2:<>m__0(Task)
System.Threading.Tasks.<ContinueWith>c__AnonStorey1:<>m__0()
System.Threading.Tasks.Task:<immediateExecutor>m__1(Action)
System.Threading.Tasks.Task`1:RunContinuations()
System.Threading.Tasks.Task`1:TrySetException(AggregateException)
System.Threading.Tasks.TaskCompletionSource`1:SetException(Exception)
Firebase.Auth.<GetTask>c__AnonStorey0:<>m__0()
Firebase.Auth.Future_User:SWIG_CompletionDispatcher(Int32)
Firebase.AppUtil:PollCallbacks()
Firebase.Platform.FirebaseMonoBehaviour:Update()
My RequestLogin() function looks like this :
public void RequestLogin(string id, string token, bool useId)
{
Credential credential;
if (useId)
{
credential = GoogleAuthProvider.GetCredential(id, token);
}
else
{
credential = FacebookAuthProvider.GetCredential(token);
}
if (credential != null)
{
auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("SignInWithCredentialAsync was canceled.");
return;
}
if (task.IsFaulted)
{
AggregateException ex = task.Exception as AggregateException;
if (ex != null)
{
FirebaseException fbEx = null;
foreach (Exception e in ex.InnerExceptions)
{
fbEx = e as FirebaseException;
if (fbEx != null)
{
Debug.LogError("Encountered a FirebaseException:" + fbEx.Message);
fbEx = null;
}
}
}
return;
}
if (task.IsCompleted)
{
FirebaseUser newUser = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
newUser.DisplayName, newUser.UserId);
_user = auth.CurrentUser;
_gameController.ActivateScene(GameController.Scene.GAME);
}
});
}
}
As you can see I'm not finding any more details in the exceptions.
Anyone know how to solve this? And why it only happens from the second launch and onwards and not on the first login with Google?
Any help would be much appreciated!
Edit:
At times I also get this which might be related:
System.ObjectDisposedException: The object was used after being disposed.
at System.Net.Sockets.Socket.get_Available () [0x00000] in <filename unknown>:0
at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, Int32 offset, Int32 size, System.AsyncCallback callback, System.Object state) [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (Mono.Security.Protocol.Tls.Alert alert) [0x00000] in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0
I have Xamarin Forms app supporting iOS and Android. It works correctly on Android in release mode. On iOS, it doesn't work in release mode but works in Debug mode. It's crashing when clicked on a button which calls few functions. I have attached error log below. The strange thing is, it works on Simulator in release mode.
Error log:
Incident Identifier: 391C564C-028D-4084-BC4A-21ED49BB1F25
CrashReporter Key: 30B4418D-AA04-4575-97A3-97A9F491C62D
Hardware Model: iPhone7,2
Process: TestApp.iOS [600]
Path: /var/containers/Bundle/Application/7F4E5392-9BEA-4578-9E23-02112B61EB96/TestApp.iOS.app/TestApp.iOS
Identifier: uk.co.company.testapp
Version: 0.0.1 (1.0)
Code Type: ARM-64
Parent Process: ??? [1]
Date/Time: 2018-01-22T13:02:31Z
Launch Time: 2018-01-22T13:02:23Z
OS Version: iPhone OS 9.3.2 (13F69)
Report Version: 104-Xamarin
Exception Type: SIGABRT
Exception Codes: #0 at 0x180da811c
Crashed Thread: 0
Application Specific Information:
*** Terminating app due to uncaught exception 'System.ArgumentNullException', reason: 'System.ArgumentNullException: Value cannot be null.'
Xamarin Exception Stack:
Parameter name: method
at System.Linq.Expressions.Expression.Call (System.Linq.Expressions.Expression instance, System.Reflection.MethodInfo method, System.Collections.Generic.IEnumerable`1[T] arguments) [0x00111] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/MethodCallExpression.cs:1239
at System.Linq.Expressions.Expression.Call (System.Linq.Expressions.Expression instance, System.Reflection.MethodInfo method, System.Linq.Expressions.Expression[] arguments) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/MethodCallExpression.cs:1046
at System.Linq.Expressions.Expression.Call (System.Reflection.MethodInfo method, System.Linq.Expressions.Expression[] arguments) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/MethodCallExpression.cs:1001
at System.Dynamic.ExpandoObject+MetaExpando.BindSetMember (System.Dynamic.SetMemberBinder binder, System.Dynamic.DynamicMetaObject value) [0x00033] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Dynamic/ExpandoObject.cs:863
at System.Dynamic.SetMemberBinder.Bind (System.Dynamic.DynamicMetaObject target, System.Dynamic.DynamicMetaObject[] args) [0x00035] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Dynamic/SetMemberBinder.cs:57
at System.Dynamic.DynamicMetaObjectBinder.Bind (System.Object[] args, System.Collections.ObjectModel.ReadOnlyCollection`1[T] parameters, System.Linq.Expressions.LabelTarget returnLabel) [0x000c6] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Dynamic/DynamicMetaObjectBinder.cs:90
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T] (System.Runtime.CompilerServices.CallSite`1[T] site, System.Object[] args) [0x00019] in <8bc31b0df50a4d32b3f1d5af764165ad>:0
at System.Runtime.CompilerServices.CallSiteOps.Bind[T] (System.Runtime.CompilerServices.CallSiteBinder binder, System.Runtime.CompilerServices.CallSite`1[T] site, System.Object[] args) [0x00000] in <8bc31b0df50a4d32b3f1d5af764165ad>:0
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00032] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:305
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:152
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Exception source) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:156
at System.Linq.Expressions.Interpreter.ExceptionHelpers.UnwrapAndRethrow (System.Reflection.TargetInvocationException exception) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/Utilities.cs:172
at System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.Run (System.Linq.Expressions.Interpreter.InterpretedFrame frame) [0x00035] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/CallInstruction.cs:327
at System.Linq.Expressions.Interpreter.Interpreter.Run (System.Linq.Expressions.Interpreter.InterpretedFrame frame) [0x00015] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/external/corefx/src/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/Interpreter.cs:63
at System.Linq.Expressions.Interpreter.LightLambda.Run3[T0,T1,T2,TRet] (T0 arg0, T1 arg1, T2 arg2) [0x00038] in <8bc31b0df50a4d32b3f1d5af764165ad>:0
at TestApp.LoginPage+<onLoginClicked>d__1.MoveNext () [0x00205] in <42b3f78eef3b4fad8ca201e1a739e68b>:0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:152
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1018
at UIKit.UIKitSynchronizationContext+<Post>c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIKitSynchronizationContext.cs:24
at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/Foundation/NSAction.cs:163
at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIApplication.cs:79
at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIApplication.cs:63
at TestApp.iOS.Application.Main (System.String[] args) [0x00000] in <52e34ea9026340479b8dc6a53c640f1e>:0
EDIT:
I have an interesting finding. I'm calling onLoginClicked function on the touch of a button, which then calls PostData function which makes a REST Call to send data to the server. Whenever the PostData function is called, app crashes.
If I move all the code from PostData function to onLoginClicked function, it works!
Please find additional information below:
I tried cleaning and rebuilding the solution but, it didn't work.
There is no point in putting break points on each line in the PostData method as the app is crashing only in release mode, but works in debug mode.
The app crashes in onLoginClicked method at a line where PostData function is called i.e.
string responseData = await PostData(user, "auth/login");
When I tried putting some alerts in PostData function to see what
point it reaches but found that it doesn't even hit the very first
line in that method. This is very strange.
Code:
async void onLoginClicked(object sender, System.EventArgs e)
{
string error = "";
if (txtEmail.Text == null || txtEmail.Text == "")
{
error += Constants.ERR_BLANK_EMAIL + "\r\n";
}
else if (txtEmail.Text.Length < 6)
{
error += Constants.ERR_EMAIL_LENGTH + "\r\n";
}
else if (!Common.isEmailValid(txtEmail.Text))
{
error += Constants.ERR_EMAIL_VALIDATION + "\r\n";
}
if (txtPassword.Text == null || txtPassword.Text == "")
{
error += Constants.ERR_BLANK_PASSWORD;
}
if (error != "")
{
lblError.Text = error;
errorContainer.IsVisible = true;
return;
}
else
{
errorContainer.IsVisible = false;
}
if (CrossConnectivity.Current.IsConnected)
{
var loadingPage = new LoadingPage();
await Navigation.PushPopupAsync(loadingPage);
var device_token = App.channelId;
dynamic user = new System.Dynamic.ExpandoObject();
user.email = txtEmail.Text;
user.user_type = "b2b";
user.device_token = device_token;
user.password = txtPassword.Text;
if (Device.RuntimePlatform == Device.iOS)
{
user.device_type = "ios";
}else{
user.device_type = "android";
}
string responseData = await PostData(user, "auth/login");
dynamic responseObj = JObject.Parse(responseData);
if (responseObj["error_code"].Value == 0)
{
var data = responseObj["data"];
Constants.user = Common.GetUserObject(data.ToString());
Helpers.Settings.Password = "" + txtPassword.Text;
Helpers.Settings.UserId = "" + Constants.user.userId;
Helpers.Settings.accessToken = ""+data.access_token;
Helpers.Settings.Email = "" + txtEmail.Text;
var outletResp = responseObj["outlet_details"];
var outlet_count = outletResp.Count;
if(outlet_count>0)
{
Constants.outlets = new List<Outlet>();
foreach(var store in outletResp){
Outlet shop = new Outlet();
shop.access_token = store["access_token"];
shop.email = store["email"];
shop.user_id = store["id"];
shop.master_id = store["master_id"];
shop.outlet_id = store["outlet_id"];
shop.post_code = store["post_code"];
shop.profile_pic = store["profile_pic"];
shop.retailer_id = store["retailer_id"];
shop.retailer_image = store["retailer_image"];
shop.store_name = store["store_name"];
shop.tutorial_pricing_tool = int.Parse(""+store["tutorial_pricing_tool"]);
Constants.outlets.Add(shop);
}
}
var isPinSet = Helpers.Settings.PinSet;
await Navigation.RemovePopupPageAsync(loadingPage);
if (responseObj.data.pin==0 || !isPinSet){
App.Current.MainPage = new NavigationPage(new SetPinPage(false));
}
else{
App.Current.MainPage = new NavigationPage(new StoreListPage());
}
}
else
{
await Navigation.RemovePopupPageAsync(loadingPage);
if (responseObj["error_code"].Value == 1)
lblError.Text = responseObj["error"];
else
lblError.Text = responseObj["message"];
errorContainer.IsVisible = true;
}
}
else
{
await DisplayAlert(Constants.APP_TITLE, "Please check your internet connection.", "OK");
}
}
async public Task<string> PostData(System.Dynamic.ExpandoObject args, string actionUrl)
{
string responseData = "";
HttpClient client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
var param = Constants.JWT ? GetJWTToken(args, actionUrl) : JsonConvert.SerializeObject(args);
var content = new StringContent(param, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Add("Authorization", param);
client.DefaultRequestHeaders.Add("X-Device-Type", "android");
client.DefaultRequestHeaders.Add("X-APP-Type", "b2b");
client.DefaultRequestHeaders.Add("X-APP-Platform", "xamarin");
HttpResponseMessage response = null;
response = await client.PostAsync(Constants.BaseUrl + actionUrl, content);
if (response.IsSuccessStatusCode)
{
response.EnsureSuccessStatusCode();
}
responseData = await response.Content.ReadAsStringAsync();
if (Constants.JWT)
{
var resp = JObject.Parse(responseData);
var respToken = resp["token"];
var rtokenStr = respToken.ToObject<String>();
var respPayloadStr = rtokenStr.Split('.');
byte[] data = JWTLibrary.Converter.Base64UrlDecode(respPayloadStr[1]);
responseData = JWTLibrary.Converter.GetStringFromBytes(data);
}
return responseData;
}
private string GetJWTToken(System.Dynamic.ExpandoObject args, string actionUrl)
{
var dt = DateTime.Now;
var ticks = dt.Ticks;
var currentSec = ticks / TimeSpan.TicksPerSecond;
var newEndTime = currentSec + 60;
Object payload = new Dictionary<string, object>()
{
{ "iat", currentSec },
{ "nbf", currentSec },
{ "exp", newEndTime },
{ "iss", actionUrl },
{ "jti", "" },
{ "bat_data", args }
};
var secret_key = "key";
dynamic n_header = new System.Dynamic.ExpandoObject();
n_header.typ = "jwt";
n_header.alg = "HS256";
byte[] headerBytes = JWTLibrary.Converter.GetBytesFromString(JsonConvert.SerializeObject(n_header));
byte[] payloadBytes = JWTLibrary.Converter.GetBytesFromString(JsonConvert.SerializeObject(payload));
var enc_header = JWTLibrary.Converter.Base64UrlEncode(headerBytes);
var enc_payload = JWTLibrary.Converter.Base64UrlEncode(payloadBytes);
string jwt_token = enc_header + "." + enc_payload;
var sh_h256 = JWTLibrary.Converter.CreateToken(jwt_token, secret_key);
var jwt_enc_signature = JWTLibrary.Converter.Base64UrlEncode(sh_h256);
jwt_token = jwt_token + "." + jwt_enc_signature;
return jwt_token;
}
I'm afraid the problem was caused by dynamic keyword.
The DynamicMethod class is a part of the set of runtime code generation features that reside with System.Reflection.Emit. However,System.Reflection.Emit API is not available in iOS.
Detail refer to Why can’t I use the “dynamic” C# keyword in Xamarin.iOS?
My question concerns translating to F# the answer for this stackoverflow question. I am using the ZeroMQ C# CLR package.
Here is part of the C# (from the answer to the linked post):
ZSocket[] sockets = { receiver1, receiver2 };
ZPollItem[] pollItems = { ZPollItem.CreateReceiver(), ZPollItem.CreateReceiver() };
ZError error;
ZMessage[] msg;
while (true)
{
if (sockets.PollIn(pollItems, out msg, out error, timeout))
{
if (msg[0] != null)
{
// The first message gotten from receiver1
}
if (msg[1] != null)
{
// The second message gotten from receiver2
}
}
}
Here is my attempt at the translation:
let ctx = new ZeroMQ.ZContext()
let sub1 = new ZeroMQ.ZSocket(ctx, ZeroMQ.ZSocketType.SUB)
sub1.SubscribeAll()
sub1.Connect("tcp://localhost:3001")
let sub2 = new ZeroMQ.ZSocket(ctx, ZeroMQ.ZSocketType.SUB)
sub2.SubscribeAll()
sub2.Connect("tcp://localhost:3002")
let timeout = System.TimeSpan.FromMilliseconds(10.)
let sockets = [|sub1; sub2|]
let pollItems = [|ZeroMQ.ZPollItem.CreateReceiver(); ZeroMQ.ZPollItem.CreateReceiver()|]
let mutable error = ZeroMQ.ZError
let mutable msg = Array.init<ZeroMQ.ZMessage> 2 // ??? C#: ZMessage[] msg;
while true do
if ZeroMQ.ZPollItems.PollIn(pollItems, &msg, &error, timeout) then // no overloads match
if msg.[0] <> null then
() // work
if msg.[1] <> null then
() // work
()
Maybe the no overload error on the PollIn method line resolves if the ZMessage[] msg is properly defined in F#. I think the library itself is besides the point but happy to provide further details if needed. My main problem is I don't understand C# and barely understand F#.
As the compiler wrote - there is no such overload. Just look at what the function expects to receive:
You forgot to specify the socket as the first parameter.
Timeout must be of type Nullable:
So...
open ZeroMQ
open System
let ctx = new ZContext()
let sub1 = new ZSocket(ctx, ZSocketType.SUB)
sub1.SubscribeAll()
sub1.Connect("tcp://localhost:3001")
let sub2 = new ZSocket(ctx, ZSocketType.SUB)
sub2.SubscribeAll()
sub2.Connect("tcp://localhost:3002")
let timeout = TimeSpan.FromMilliseconds(10.) |> Nullable
let sockets = [|sub1; sub2|]
let pollItems = [|ZPollItem.CreateReceiver(); ZPollItem.CreateReceiver()|]
let mutable error = null
let mutable msg = null
while true do
if ZPollItems.PollIn(sockets, pollItems, &msg, &error, timeout) then
if msg.[0] <> null then
() // work
if msg.[1] <> null then
() // work
()
I have this code here: (Playground link)
use std::thread;
use std::sync::mpsc::channel;
fn run<T: Send>(task: fn() -> T) -> T {
let (tx, rx) = channel();
thread::spawn(move || {
tx.send(task());
});
rx.recv().unwrap()
}
fn main() {
let task = || 1 + 2;
let result = run(task);
println!("{}", result);
}
But I'm getting a lifetime error I can't figure out.
<anon>:6:5: 6:18 error: the parameter type `T` may not live long enough [E0310]
<anon>:6 thread::spawn(move || {
^~~~~~~~~~~~~
<anon>:6:5: 6:18 help: consider adding an explicit lifetime bound `T: 'static`...
<anon>:6:5: 6:18 note: ...so that captured variable `tx` does not outlive the enclosing closure
<anon>:6 thread::spawn(move || {
^~~~~~~~~~~~~
<anon>:15:22: 15:26 error: mismatched types:
expected `fn() -> _`,
found `[closure <anon>:13:16: 13:24]`
(expected fn pointer,
found closure) [E0308]
<anon>:15 let result = run(task);
^~~~
Any suggestions? Thanks!
The error message suggests adding a 'static bound to the type parameter T. If you do this, it will get rid of the first error:
fn run<T: Send + 'static>(task: fn() -> T) -> T
The 'static bound is needed to guarantee that the value returned by task can outlive the function where task runs. Read more about the 'static lifetime.
The second error is that you are passing a closure, while run expects a function pointer. One way to fix this is by changing task from a closure to a fn:
fn task() -> u32 { 1 + 2 }
Here's the complete working code:
use std::thread;
use std::sync::mpsc::channel;
fn run<T: Send + 'static>(task: fn() -> T) -> T {
let (tx, rx) = channel();
thread::spawn(move || {
tx.send(task());
});
rx.recv().unwrap()
}
fn main() {
fn task() -> u32 { 1 + 2 }
let result = run(task);
println!("{}", result);
}