How do I create a dynamic object in Blazor WebAssembly? - blazor-webassembly

The code below is one of the Blazor WebAssembly example.
#code {
protected override async Task OnInitializedAsync()
{
string _baseURL = "";
int caseSwitch = new Random().Next(1, 4);
switch (caseSwitch)
{
case 1:
_baseURL = "https://randomuser.me/api/";
break;
case 2:
_baseURL = "https://reqres.in/api/users?page=2";
break;
default:
_baseURL = "https://jsonplaceholder.typicode.com/todos";
break;
}
dynamic? items = await Http.GetFromJsonAsync<dynamic>(_baseURL);
}
}
and when I did a breakpoint on the items variable, it is null. How do I create a dynamic object so that when any of the Rest API is called, it can fit into the object dynamically without me needing to create 3 different classes with it own different properties? Thanks

Related

Old ASP.NET code works on one computer, not on another?

So in my global.asax, I've got the following code:
Inventory.BusinessTier bt = new Inventory.BusinessTier();
string UserLogin = bt.ExtractLogin (Request.ServerVariables ["AUTH_USER"]);
Inventory.User myUser = new Inventory.User (UserLogin);
Session ["User"] = myUser;
It works just fine on one development PC, but using the same version of Visual Studio, it craps out on the third line with this error:
System.TypeInitializationException: 'The type initializer for
'Inventory.DataTier' threw an exception.'
Inner Exception
NullReferenceException: Object reference not set to an instance of an
object.
Other than a line adding impersonation in my web.config (it has to be there now), I haven't changed a single thing. Is there a way to get more info on this? I can't even trace it, because if I put a debug line in the User object constructor, it never hits it. I'm at a bit of a loss. Would appreciate any advice.
EDIT to answer questions below:
InventoryUser is a very simple user object that reads the current from the database and stores some basic user info in properties, such as UserID, Role, RoleID, and IsAdmin.
The DataTier class is a class that interacts with the database. It is used in multiple projects, so I'm quite sure it's not the problem. I tried to paste in the code anyway, but it exceeded the limit for a post.
I'm reasonably sure the problem is related to the user class. It's short, so I can paste it in here:
using System;
using System.Data;
// This is the user business object. It contains information pertaining to the current user of the application. Notably, it
// contains the department ID, which determines what inventory items the user will see when using the application. Only
// specified employees with admin access can see all items for all departments, and that is determined by a specific department ID.
namespace Inventory {
public class User {
private Guid _UserID;
private Guid _RoleID;
private Guid _UserDepartmentID;
private string _UserRole = "";
private string _UserName = "";
private bool _IsAuthorizedUser = false;
private bool _IsAdmin = false;
// Attribute declarations
public Guid UserID {
get {
return _UserID;
}
set {
_UserID = value;
}
}
public string UserRole {
get {
return _UserRole;
}
set {
_UserRole = value;
}
}
public Guid RoleID {
get {
return _RoleID;
}
set {
_RoleID = value;
}
}
public string UserName {
get {
return _UserName;
}
set {
_UserName = value;
}
}
public Guid UserDepartmentID {
get {
return _UserDepartmentID;
}
set {
_UserDepartmentID = value;
}
}
public bool IsAdmin {
get {
return _IsAdmin;
}
set {
_IsAdmin = value;
}
}
public bool IsAuthorizedUser {
get {
return _IsAuthorizedUser;
}
set {
_IsAuthorizedUser = value;
}
}
// -----------------
// - Constructor -
// -----------------
public User (string UserLogin) {
string ShortUserLogin = ExtractLogin (UserLogin);
GetUser (ShortUserLogin);
}
// ------------------
// - ExtractLogin -
// ------------------
public string ExtractLogin (string Login) {
// The domain and "\" symbol must be removed from the string, leaving only the user name.
int pos = Login.IndexOf (#"\");
return Login.Substring (pos + 1, Login.Length - pos - 1);
}
// -------------
// - GetUser -
// -------------
// This method is called to fill the user object based on the user's login. It ultimately gets authorized user data
// from the user table.
public void GetUser (string UserName) {
DataTier dt1 = new DataTier();
DataTable dt = dt1.GetUserInfo (UserName);
int RecordCount = dt.Rows.Count;
switch (RecordCount) {
case 1: // There is one user name match, as there should be. This is the likely situation.
DataRow dr = dt.Rows[0];
UserID = (Guid)dr ["UserID"];
UserRole = (string)dr ["UserRole"];
RoleID = (Guid)dr ["RoleID"];
this.UserName = UserName;
UserDepartmentID = (Guid)dr ["DepartmentID"];
IsAdmin = (bool)dr ["IsAdmin"];
IsAuthorizedUser = true;
break;
case 0: // There are no user name matches (unauthorized use).
IsAdmin = false;
IsAuthorizedUser = false;
break;
default: // There are multiple user name matches (problem!).
IsAdmin = false;
IsAuthorizedUser = false;
break;
}
}
}
}

How to get result of HttpRequest?

I'm writing the game for mobile using dart. My level-config stored as json. Via httpRequest I get JSON from server and then parse my json. It should create a Level-Object. I want to use it in my model. But I can't assign it to the level-reference in my model (model.level). After HttpRequest it's value is still the same (null). My idea was also to use some art of callback, but I don't know how...
static void load(final int levelNr, Game model) {
final String path = "../json/$levelNr.json";
HttpRequest.getString(path).then((lvlJson) {
Map data = JSON.decode(lvlJson);
Level level = _levelFromMap(data);
model.level = level;
});
}
You can use callback or async await
1. Callback
static void load(final int levelNr, void callbackFunction(Level level)) {
final String path = "../json/$levelNr.json";
HttpRequest.getString(path).then((lvlJson) {
Map data = JSON.decode(lvlJson);
Level level = _levelFromMap(data);
callbackFunction(level);
});
}
Usage:
load(levelNrValue, (level) {
model.level = level;
//refresh view or data to reflect the change in model.
})
2. async and await
static Future<Level> load(final int levelNr) async {
final String path = "../json/$levelNr.json";
final response = await HttpRequest.getString(path);
Map data = JSON.decode(lvlJson);
return _levelFromMap(data);
}
Usage:
1) Using callback at calling place:
load(levelNrValue).then((level) {
model.level = level;
//refresh view or data to reflect the change in model.
});
2) Using async in calling place also:
final level = await load(levelNrValue);
model.level = level;
Note: the above two lines should be inside some async method.
void loadDate(int levelNrValue, Game model) async {
final level = await load(levelNrValue);
model.level = level;
//refresh view or data to reflect the change in model.
}
Maybe the request is finishing in an error which might not be noticed.
Try adding a catchError:
static void load(final int levelNr, Game model) {
final String path = "../json/$levelNr.json";
HttpRequest.getString(path).then((lvlJson) {
Map data = JSON.decode(lvlJson);
Level level = _levelFromMap(data);
model.level = level;
})
.catchError((Error error) {
print(error.toString());
});;
}

WebAPI call hangs when return a large amount of data

I have a web api call that I recently added to my app. I returns a complete list of all countries, states and cities in the app (currently 486 rows) I perform this call when all of the reference data for my application loads (I have a base loading page and call the function in my startup class to load all the data there). The challenge is that the call to get all my countries.... hangs and eventually I get "The operation was canceled" error. If I modify my stored procedure that selects the data from the database on the server to only return say 20 rows, it runs fine. Any suggestions?
Below is the code from the startup class:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace GBarScene
{
class StartUpClass
{
public event GeneralDataLoad BaseDataLoadComplete;
public async Task<GBSStartUpEventArgs> ProcessStartup()
{
GBSStartUpEventArgs lobj_EventArgs;
lobj_EventArgs = new GBSStartUpEventArgs();
App.InStartUpDataLoad = true;
try
{
if (!App.IsGeolocationEnabled)
{
lobj_EventArgs.ErrorOccurred = true;
lobj_EventArgs.ShowRetry = true;
lobj_EventArgs.ShowWebSite = false;
lobj_EventArgs.ErrorMessage = resourcestrings.GetValue("NoLocationServicesMessage");
}
else if (!App.InternetIsAvailable)
{
lobj_EventArgs.ErrorOccurred = true;
lobj_EventArgs.ErrorMessage = resourcestrings.GetValue("NoInternetConnectionFound");
lobj_EventArgs.ShowRetry = true;
lobj_EventArgs.ShowWebSite = false;
}
else
{
Debug.WriteLine("Process StartUp");
await Task.Delay(500);
//Reset values
ViewModelObjects.DayOfWeek.DataLoadProcessed = false;
ViewModelObjects.Languages.DataLoadProcessed = false;
if (await ViewModelObjects.DayOfWeek.LoadData() == false)
// //try it once more
await ViewModelObjects.DayOfWeek.LoadData();
Debug.WriteLine("GBar After DayofWeek Load");
await ViewModelObjects.Languages.LoadData();
Debug.WriteLine("GBar After Languages Load");
if ((ge_AppMode)ViewModelObjects.AppSettings.AppMode == ge_AppMode.CitySelected)
{
//We need to reload the NearbyCities and set the selected one
await ViewModelObjects.NearbyCities.LoadData();
}
Debug.WriteLine("Before load of coutries");
await ViewModelObjects.CountryStateCity.LoadData();
Debug.WriteLine("After load of coutries");
Debug.WriteLine("Count: " + ViewModelObjects.CountryStateCity.CountryItems_ForList.Count.ToString());
ViewModelObjects.NumberOfResults.LoadData();
ViewModelObjects.Perspectives.LoadData();
ViewModelObjects.SearchRadiuses.LoadData();
ViewModelObjects.UseMetric.LoadData();
while (!ViewModelObjects.DayOfWeek.DataLoadProcessed && !ViewModelObjects.Languages.DataLoadProcessed && !App.IsGeolocationEnabled)
{
await Task.Delay(100);
}
if (App.BaseDataLoadError)
{
lobj_EventArgs.ErrorOccurred = true;
lobj_EventArgs.ShowRetry = true;
lobj_EventArgs.ShowWebSite = true;
lobj_EventArgs.ErrorMessage = resourcestrings.GetValue("ErrorLoadingReferenceData");
}
}
Debug.WriteLine("StartUp Process Ended");
BaseDataLoadComplete(this, lobj_EventArgs);
}
catch (Exception ex)
{
App.ProcessException(ex);
}
App.InStartUpDataLoad = false;
return lobj_EventArgs;
}
}
}
This is the helper class that makes all the WebAPI calls:
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace GBarScene
{
public class WebAPICaller: IDisposable
{
HttpClient iobj_HTTPClient = null;
public void Dispose()
{
if (iobj_HTTPClient != null)
iobj_HTTPClient.Dispose();
}
public async Task<string> HTTPGetWebServiceAsync(string ps_URI)
{
string ls_Response = "";
string ls_JSONData = "";
string ls_Prefix = "";
try
{
iobj_HTTPClient = await GetClient();
switch (Device.RuntimePlatform)
{
case Device.Android:
ls_Prefix = App.APIStandardPrefix;
break;
//case Device.Android:
// ls_Prefix = App.APISecurePrefix;
// break;
//case Device.Windows:
//case Device.WinPhone:
// ls_Prefix = App.APISecurePrefix;
// break;
default:
ls_Prefix = App.APISecurePrefix;
break;
}
Debug.WriteLine("before api call");
iobj_HTTPClient.BaseAddress = new Uri(ls_Prefix);
ls_JSONData = await iobj_HTTPClient.GetStringAsync(ps_URI);
Debug.WriteLine("after api call");
ls_Response = System.Net.WebUtility.HtmlDecode(ls_JSONData);
}
catch (Exception ex)
{
Debug.WriteLine("api call error");
App.ProcessException(ex);
}
return ls_Response;
}
public async Task<bool> HTTPPostWebService(string ps_URI, object pobj_BodyObject)
{
HttpResponseMessage lobj_HTTPResponse = null;
bool lb_Response = false;
HttpContent lobj_Content = null;
try
{
if (iobj_HTTPClient != null)
iobj_HTTPClient = await GetClient();
iobj_HTTPClient.BaseAddress = new Uri(App.APISecurePrefix);
lobj_Content = new StringContent(JsonConvert.SerializeObject(pobj_BodyObject == null ? "" : pobj_BodyObject));
lobj_Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
lobj_HTTPResponse = await iobj_HTTPClient.PostAsync(ps_URI, lobj_Content);
if (!lobj_HTTPResponse.IsSuccessStatusCode)
{
Exception lobj_Exception = new Exception(lobj_HTTPResponse.ToString());
lobj_Exception.Source = "HTTPGetWebService for: " + ps_URI;
App.ProcessException(lobj_Exception);
}
else
{
lb_Response = true;
}
}
catch (Exception ex)
{
App.ProcessException(ex);
}
finally
{
if (lobj_HTTPResponse != null)
{
lobj_HTTPResponse.Dispose();
}
//Debug.WriteLine("WebAPICaller-CallWebService-1: Done");
}
return lb_Response;
}
private async Task<HttpClient> GetClient()
{
HttpClient lobj_HTTPClient = null;
if (lobj_HTTPClient == null)
{
lobj_HTTPClient = new HttpClient();
lobj_HTTPClient.DefaultRequestHeaders.Add("Accept", "application/json");
lobj_HTTPClient.MaxResponseContentBufferSize = 2147483647;
lobj_HTTPClient.Timeout = new TimeSpan(0,0,0,0,60000);
}
return lobj_HTTPClient;
}
}
}
Sorry I forget to include the method in the CountryStateCity view model that calls the webapi helper class.
public async Task<bool> LoadData()
{
string ls_Response = "";
string ls_WorkURI = "";
WebAPICaller lobj_WebAPICaller = null;
bool lb_DataLoaded = false;
try
{
IsDataLoaded = false;
//Debug.WriteLine("City Data Load");
lobj_WebAPICaller = new WebAPICaller();
ls_WorkURI = ic_CoutryStateCityAPIUrl.Replace("{Language}", "EN");
ls_Response = await lobj_WebAPICaller.HTTPGetWebServiceAsync(ls_WorkURI);
if (ls_Response.Trim().Length == 0)
{
AddErrorEntry();
}
else
{
CountryItems_ForList = new ObservableCollection<GBSCountry_ForList>();
StateItems_ForList = new ObservableCollection<GBSState_ForList>();
CityItems_ForList = new ObservableCollection<GBSCity_ForList>();
iobj_CountryStateCity = JsonConvert.DeserializeObject<ObservableCollection<GBSCountryStateCity>>(ls_Response);
//Now load the display lists
CountryItems_ForList = new ObservableCollection<GBSCountry_ForList>(
(from lobj_Country in iobj_CountryStateCity
select new GBSCountry_ForList()
{
ID = lobj_Country.Country_Code,
Value = lobj_Country.Country_Name_Text
}).Distinct().ToList());
CountryItems_ForList.Insert(0, new GBSCountry_ForList
{
ID = "XX",
Value = "Base Value"
});
lb_DataLoaded = true;
}
}
catch (Exception ex)
{
AddErrorEntry();
App.ProcessException(ex);
}
finally
{
IsDataLoaded = true;
if (lobj_WebAPICaller != null)
lobj_WebAPICaller.Dispose();
}
return lb_DataLoaded;
}
So after much time, I believe I figured out what the problem is. The problem started to manifest itself again with smaller amounts of data and I could not figure out why. The problem appeared. The issue appears to be the IP address I was using. (I was using the IP address of the actual laptop I was hosting both the App and WebAPIs on.) It appears you have to use one of the other network adaptors for the emulator to have this work reliably.
Here are the steps I used to resolved this:
I launched my Windows 10 mobile emulator.
Click on the >> (Tools) icon in the tool bar of the emulator.
Click on the Network tab of the Additional Tools window.
Look in the list for the network adaptor labeled Desktop Adaptor #1 and copy the IP address.
Edit the Applicationhost.config file in the folder of the WebAPI project.
Find the entry in the file for site name="XXXXX" where XXXXX is the name of the Visual Studio project you are hosting your WebAPIs in.
Within the section of the entry for your WebAPI project, add a binding for the IP address you copied from in step 4. It should look something like this:
<binding protocol="http" bindingInformation="*:56952:169.254.69.220" />
Where 56952 is the port my IIS Express is hosting the WebAPIs on and 169.254.69.220 is the IP address I copied from step 4. After adding this, I was able to connect to locally hosted WebAPIs in IIS Express.
Hope this helps.

Set a job to failed using Hangfire with ASP.NET?

I have an ASP.NET app which sends emails whenever the user signs up in the web site. I'm using hangfire in order to manage the jobs and postal in order to send emails.
It all works great, but here's the thing:
I want the superuser to change how many times the APP can send the email before deleting the job.
Here's my code
public static void WelcomeUser(DBContexts.Notifications not)
{
try{
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var engines = new ViewEngineCollection();
engines.Add(new FileSystemRazorViewEngine(viewsPath));
Postal.EmailService service = new Postal.EmailService(engines);
WelcomeUserMail welcomeUserMail = new WelcomeUserMail();
welcomeUserMail.To = not.ReceiverEmail;
welcomeUserMail.UserEmail = not.ReceiverEmail;
welcomeUserMail.From = BaseNotification.GetEmailFrom();
service.Send(welcomeUserMail);
}
catch(Exception e)
{
DBContexts.DBModel dbModel = new DBModel();
DBContexts.Notifications notificacionBD = dbModel.Notifications.Find(not.NotificationID);
notificacionBD.Status = false;
notificacionBD.Timestamp = DateTime.Now;
notificacionBD.Error = e.Message;
int numberOfRetriesAllowed = ParameterHelper.getNumberOfRetriesAllowed();
if (notificacionBD.Retries > numberOfRetriesAllowed)
{
//In this case Hangfire won't put this job in the failed section but rather in the processed section.
dbModel.SaveChanges();
}
else
{
notificacionBD.Retries++;
dbModel.SaveChanges();
throw new Exception(e.Message);
}
}
}
Why not just add attributes to handle it automatically?
[AutomaticRetry(Attempts = 10, LogEvents = true, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public void MyTask(){
//doing stuff
}
Or you could just make your own attribute that mimics the AutommaticRetryAttribute class but you handle it how you want?
https://github.com/HangfireIO/Hangfire/blob/a5761072f18ff4caa80910cda4652970cf52e693/src/Hangfire.Core/AutomaticRetryAttribute.cs

How do I use System.Activities.Validation.GetParentChain?

I've got an Outer activity which has a Body onto which you drag other activities. I then have several Inner activities, which MUST be a descendent of an Outer activity. I'd like to add design-time validation to ensure the Inner is placed within an Outer.
I've heard that I "can use System.Activities.Validation.GetParentChain to enumerate all of the parents of an activity during the validation step". But even after reading the documentation for the class, I have no idea how to use it.
I would think I use it inside CacheMetadata in my Inner class. I'd like to use have a foreach(var ancestor in parentChain) { ... }, and make sure at least one ancestor is of type Outer. Not sure how to do that.
Can anyone explain how to validate at design time that an Inner activity is a descendant of an Outer activity?
As you can see through the documentation GetParentChain is a regular CodeActivity. You can use it in conjunction with Activity.Constraints.
Constraints are executed at design time, just like CacheMetadata(), but you have the ability to access the context (the ValidationContext at this point, of course). Otherwise you wouldn't be able to known the upper level activities.
Lets see if I understood your case right and if this example covers it. Basically it loops through IEnumerable<Activity> returned by GetParentChain and checks if any of Inner's parents is an Outer. This way it ensures that Inner is always inside an Outer.
public sealed class Inner : CodeActivity
{
public Inner()
{
Constraints.Add(MustBeInsideOuterActivityConstraint());
}
protected override void Execute(CodeActivityContext context)
{
// Execution logic here
}
private Constraint<Inner> MustBeInsideOuterActivityConstraint()
{
var activityBeingValidated = new DelegateInArgument<Inner>();
var validationContext = new DelegateInArgument<ValidationContext>();
var parent = new DelegateInArgument<Activity>();
var parentIsOuter = new Variable<bool>();
return new Constraint<Inner>
{
Body = new ActivityAction<Inner, ValidationContext>
{
Argument1 = activityBeingValidated,
Argument2 = validationContext,
Handler = new Sequence
{
Variables =
{
parentIsOuter
},
Activities =
{
new ForEach<Activity>
{
Values = new GetParentChain
{
ValidationContext = validationContext
},
Body = new ActivityAction<Activity>
{
Argument = parent,
Handler = new If
{
Condition = new InArgument<bool>(env =>
object.Equals(parent.Get(env).GetType(), typeof(Outer))),
Then = new Assign<bool>
{
To = parentIsOuter,
Value = true
}
}
}
},
new AssertValidation
{
Assertion = parentIsOuter,
Message = "Inner must be inside Outer"
}
}
}
}
};
}
}
If you want to allow multiple Outers, you have to check them, one by one, wither with a loop through an array (using ForEach) or multiple nested Ifs.
For example, with multiple ifs, and continuing with the code above:
Handler = new If
{
Condition = new InArgument<bool>(env =>
object.Equals(parent.Get(env).GetType(), typeof(OuterONE))),
Then = new Assign<bool>
{
To = parentIsOuter,
Value = true
}
Else = new If
{
Condition = new InArgument<bool>(env =>
object.Equals(parent.Get(env).GetType(), typeof(OuterTWO))),
Then = new Assign<bool>
{
To = parentIsOuter,
Value = true
},
Else = new If
{
// and continue with other Outers
}
}
}
In short, an If-then-else statement using activities.
Other option that I've never tested but that it seems pretty plausible, and because you can use activities inside constraints, is throw all this logic inside an activity which its only job is to check if type if an Outer:
public sealed CheckIfTypeIsOuter<T> : CodeActivity<bool>
{
protected override bool Execute()
{
if (typeof(T) == typeof(Outer1))
return true;
if (typeof(T) == typeof(Outer2))
return true;
if (typeof(T) == typeof(Outer3))
return true;
if (typeof(T) == typeof(Outer4))
return true;
return false;
}
}
This way you can do it through code.
Well, I guess you get the idea!
Joao's answer is great. I took his answer and made the constraint dynamic so I could reuse it across 20+ activities without adding 80+ lines of code to each one.
The constraint is placed in it's own file ScopeActivityConstraint.cs:
using System;
using System.Activities;
using System.Activities.Statements;
using System.Activities.Validation;
namespace MyNamespace
{
public static class Constraints
{
public static Constraint<T> ScopeActivity<T>(
object activity,
object scope,
string message
)
{
var delegateType = typeof(DelegateInArgument<>).MakeGenericType(activity.GetType());
dynamic activityBeingValidated = Activator.CreateInstance(delegateType);
var validationContext = new DelegateInArgument<ValidationContext>();
var parent = new DelegateInArgument<Activity>();
var insideScope = new Variable<bool>();
Sequence handler = new Sequence
{
Variables = {
insideScope
},
Activities =
{
new ForEach<Activity>
{
Values = new GetParentChain
{
ValidationContext = validationContext
},
Body = new ActivityAction<Activity>
{
Argument = parent,
Handler = new If
{
Condition = new InArgument<bool>(env =>
object.Equals(parent.Get(env).GetType(), scope)),
Then = new Assign<bool>
{
To = insideScope,
Value = true
}
}
}
},
new AssertValidation
{
Assertion = insideScope,
Message = message
}
}
};
var activityActionType = typeof(ActivityAction<,>).MakeGenericType(
activity.GetType(),
typeof(ValidationContext)
);
dynamic constraintBody = Activator.CreateInstance(activityActionType);
constraintBody.Argument1 = activityBeingValidated;
constraintBody.Argument2 = validationContext;
constraintBody.Handler = handler;
var constraintType = typeof(Constraint<>).MakeGenericType(activity.GetType());
dynamic constraint = Activator.CreateInstance(constraintType);
constraint.Body = constraintBody;
return constraint;
}
}
}
You would then utilize it in your Inner activity:
using System.Activities;
using System.Activities.Validation;
using static MyNamespace.Constraints;
namespace MyNamespace
{
public class Inner : CodeActivity
{
public Inner()
{
Constraint<Inner> constraint = ScopeActivity<Inner>(
this,
typeof(MyNamespace.OuterScope),
"Inner activity must be placed inside an Outer Scope activity",
);
Constraints.Add(constraint);
}
protected override void Execute(CodeActivityContext context)
{
// do things
}
}
}

Resources