Radzen Blazor DropDown on dynamic data from external API - drop-down-menu

I'm getting data from an external API and the code looks like this (this part is fine):
#code {
IEnumerable<IDictionary<string, object>> data;
int count;
bool isLoading;
async Task LoadData(LoadDataArgs args)
{
isLoading = true;
var uri = new Uri("https://services.radzen.com/odata/Northwind/Employees")
.GetODataUri(filter: args.Filter, top: args.Top, skip: args.Skip, orderby: args.OrderBy, count: true);
var response = await new HttpClient().SendAsync(new HttpRequestMessage(HttpMethod.Get, uri));
var result = await response.ReadAsync<ODataServiceResult<IDictionary<string, object>>>();
data = result.Value.AsODataEnumerable();
count = result.Count;
isLoading = false;
}
}
On the dropdown menu I want to display the EmployeeID, but cannot access it (the Data="#data.Employee.ID" is incorrect and not sure what to put in there to make it work).
<RadzenDropDown Data="#data.EmployeeID" TextProperty="EmployeeID" ValueProperty="EmployeeID" Name="Dropdown1" TValue="string">
</RadzenDropDown>
Thanks!

The problem is that the Data Property is:
IEnumerable<IDictionary<string, object>> data;
It should be:
IEnumerable<Employee>data;
So then you can acess to Employee class properties.
<RadzenDropDown Data="#data.EmployeeID" TextProperty="EmployeeID" ValueProperty="EmployeeID" Name="Dropdown1" TValue="Employee">
</RadzenDropDown>

Related

Rotativa BuildFile not hitting the Action Method

I have two action methods in my Controller class:
DetailsAll: to get some data and display in the view
SaveAsPDF: Called on windows.load of DetailsAll.cshtml which should save DetailsAll view as pdf
My issue is in SaveAsPDF Action method. Here I am trying to use Rotativa ActionAsPdf and subsequently BuildFile methods to generate and save the PDF. However, when executing the line "BuildFile", it is not hitting the breakpoint in my DetailsAll Action method, subsequently causing the PDF to be generated blank.
Could you please help where I am going wrong?
[HttpGet]
public ActionResult DetailsAll()
{
var selectionBuilder = builderFactory.GetGeocodeReportSelectionViewModelBuilder();
var companyList = selectionBuilder.Build();
List<GeocodeReportViewModel> viewModel = new List<GeocodeReportViewModel>();
foreach(SelectListItem record in companyList.Companies)
{
var builder = builderFactory.GetGeocodeReportViewModelBuilder(int.Parse(record.Value));
viewModel.Add(builder.Build());
}
var model = new AllGeocodeReportViewModel
{
GeocodeReports = viewModel
};
return View(model);
}
[HttpGet]
public string SaveAsPDF()
{
var report = new ActionAsPdf("DetailsAll")
{
FileName = "OEM_GeocodeReport_" + System.DateTime.Now.ToString("MMYY") + ".pdf",
PageSize = Size.A4,
PageOrientation = Orientation.Landscape,
PageMargins = { Left = 1, Right = 1 }
};
byte[] pdf = report.BuildFile(ControllerContext);
System.IO.File.WriteAllBytes("C:\\" + report.FileName, pdf);
return "true";
}
Finally found the issue after extensive search. I need to send Authentication cookies along with the BuildFile request for this to work. Added the below code and it generates PDF correctly now:
public void SaveAsPDF()
{
var cookies = Request.Cookies.AllKeys.ToDictionary(k => k, k => Request.Cookies[k].Value);
var report = new ActionAsPdf("DetailsAll")
{
FileName = "OEM_GeocodeReport_" + System.DateTime.Now.ToString("MMyy") + ".pdf",
PageSize = Size.A4,
PageOrientation = Orientation.Portrait,
PageMargins = { Left = 3, Right = 3 },
FormsAuthenticationCookieName = System.Web.Security.FormsAuthentication.FormsCookieName,
Cookies = cookies
};
byte[] pdf = report.BuildFile(ControllerContext);
System.IO.File.WriteAllBytes("C:\\" + report.FileName, pdf);
}

what is the faster and best way to make a few million SOAP requests and save the results into SqlDb

I have a million records in my table. I want to call a soap service and i need to do process in all the records in less than one hour. and besides i should update my table , insert the requests and responses in my other tables. but the code below works on less than 10 records every time i run my app.
I know My code is wrong,, I want to know what is the best way to do it.
static async Task Send( )
{
var results = new ConcurrentDictionary<string, int>();
using (AppDbContext entities = new AppDbContext())
{
var List = entities.Request.Where(x => x.State == RequestState.InitialState).ToList();
Parallel.ForEach(Enumerable.Range(0, List.Count), async index =>
{
var selected = List.FirstOrDefault();
List.Remove( selected );
var res1 = await DoAsyncJob1(selected); ///await
// var res = CallService(selected);
var res2 = await DoAsyncJob2(selected); ///await
var res3 = await DoAsyncJob3(selected); ///await
// var responses = await Task.WhenAll(DoAsyncJob1, DoAsyncJob2, DoAsyncJob3);
// results.TryAdd(index.ToString(), res);
});
}
}
static async Task<int> DoAsyncJob1(Request item)
{
using (AppDbContext entities = new AppDbContext())
{
var bReq = new BankRequest();
bReq.Amount = Convert.ToDecimal(item.Amount);
bReq.CreatedAt = DateTime.Now;
bReq.DIBAN = item.DIBAN;
bReq.SIBAN = item.SIBAN;
entities.BankRequest.Add(bReq);
entities.SaveChanges();
}
return item.Id;
}
static async Task<int> DoAsyncJob2(Request item)
{
using (AppDbContext entities = new AppDbContext())
{
}
return item.Id;
}
static async Task<int> DoAsyncJob3(Request item)
{
using (AppDbContext entities = new AppDbContext())
{
}
return item.Id;
}
Maybe the below lines are wrong :
var selected = List.FirstOrDefault();
List.Remove( selected );
Thanks in advance..
First, it is a bad practice to use async-await within Parallel.For - you introduce only more load to the task scheduler and more overhead.
Second, you are right:
var selected = List.FirstOrDefault();
List.Remove( selected );
is very, very wrong. Your code will behave in a totally unpredictable way, due to the race conditions.

Populate SQLite database from generic "list of items"

I use a SQLite database to populate a listview with a generic list of TodoItems:
ListView.ItemsSource = await App.Database.GetItemsAsync("SELECT * FROM [TodoItem]");
I can read data of the same kind from a database source using the HttpClient class as well via
public async Task<List<TodoItem>> ReadDataAsync ()
....
Items = new List<TodoItem> ();
....
var content = await response.Content.ReadAsStringAsync ();
Items = JsonConvert.DeserializeObject <List<TodoItem>> (content);
....
return Items;
whereafter I can use this as a data source as well:
ListView.ItemsSource = await App.ReadDataAsync();
Both ways work well.
What I want now is combine both routines to accomplish a code which checks whether we have an online connection, if yes, drop the database and populate it using the result of ReadDataAsync from above, if no, leave the database alone.
I found no way to directly assign a List to my database, overwriting the whole contents, I think of something like:
App.Database.Items = await App.ReadDataAsync();
but SQLite doesn't seem to expose the data store directly. How can I accomplish this?
For android for example, you could try: There's no need to drop the database.
//Check for internet connection
var connectivityManager =
(ConnectivityManager)this.GetSystemService("connectivity");
var activeConnection = connectivityManager.ActiveNetworkInfo;
if ((activeConnection != null) && activeConnection.IsConnected)
{
//Make call to the API
var list = await App.ReadDataAsync();
//Update or Insert local records
foreach (var item in list)
{
var success = UpdateOrInsert(item);
//Do something after - like retry incase of failure
}
}
The UpdatedOrInsert method can look like:
private bool UpdateOrInsert(TodoItem item)
{
var rowsAffected = App.Database.Update(item);
if (rowsAffected == 0)
{
// The item doesn't exist in the database, therefore insert it
rowsAffected = App.Database.Insert(item);
}
var success = rowsAffected > 0;
return success;
}

Running async function in parallel using LINQ's AsParallel()

I have a Document DB repository class that has one get method like below:
private static DocumentClient client;
public async Task<TEntity> Get(string id, string partitionKey = null)
{
try
{
RequestOptions requestOptions = null;
if (partitionKey != null)
{
requestOptions = new RequestOptions { PartitionKey = new PartitionKey(partitionKey) };
}
var result = await client.ReadDocumentAsync(
UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id),
requestOptions);
return (TEntity)(dynamic)result.Resource;
}
catch (DocumentClientException e)
{
// Have logic for different exceptions actually
throw;
}
}
I have two collections - Collection1 and Collection2. Collection1 is non-partitioned whereas Collection2 is partitioned.
On the client side, I create two repository objects, one for each collection.
private static DocumentDBRepository<Collection1Item> collection1Repository = new DocumentDBRepository<Collection1Item>("Collection1");
private static DocumentDBRepository<Collection2Item> collection2Repository = new DocumentDBRepository<Collection2Item>("Collection2");
List<Collection1Item> collection1Items = await collection1Repository.GetItemsFromCollection1(); // Selects first forty documents based on time
List<UIItem> uiItems = new List<UIItem>();
foreach (var item in collection1Items)
{
var collection2Item = await storageRepository.Get(item.Collection2Reference, item.TargetId); // TargetId is my partition key for Collection2
uiItems.Add(new UIItem
{
ItemId = item.ItemId,
Collection1Reference = item.Id,
TargetId = item.TargetId,
Collection2Reference = item.Collection2Reference,
Value = collection2Item.Value
});
}
This works fine. But since it is happening sequentially with foreach, I wanted to do those Get calls in parallel. When I do it in parallel as below:
ConcurrentBag<UIItem> uiItems = new ConcurrentBag<UIItem>();
collection1Items.AsParallel().ForAll(async item => {
var collection2Item = await storageRepository.Get(item.Collection2Reference, item.TargetId); // TargetId is my partition key for Collection2
uiItems.Add(new UIItem
{
ItemId = item.ItemId,
Collection1Reference = item.Id,
TargetId = item.TargetId,
Collection2Reference = item.Collection2Reference,
Value = collection2Item.Value
});
}
);
It doesn't work and uiItems is always empty.
You don't need Parallel.For to run async operations concurrently. If they are truly asynchronous they already run concurrently.
You could collect the task returned from each operation and simply call await Task.WhenAll() on all the tasks. If you modify your lambda to create and return a UIItem, the result of await Task.WhenAll() will be a collection of UIItems. No need to modify global state from inside the concurrent operations.
For example:
var itemTasks = collection1Items.Select(async item =>
{
var collection2Item = await storageRepository.Get(item.Collection2Reference, item.TargetId);
return new UIItem
{
ItemId = item.ItemId,
Collection1Reference = item.Id,
TargetId = item.TargetId,
Collection2Reference = item.Collection2Reference,
Value = collection2Item.Value
}
});
var results= await Task.WhenAll(itemTasks);
A word of caution though - this will fire all Get operations concurrently. That may not be what you want, especially when calling a service with rate limiting.
Try simply starting tasks and waiting for all of them at the end. That would result in parallel execution.
var tasks = collection1Items.Select(async item =>
{
//var collection2Item = await storageRepository.Get...
return new UIItem
{
//...
};
});
var uiItems = await Task.WhenAll(tasks);
PLINQ is useful when working with in-memory constructs and using as many threads as possible, but if used with the async-await technique (which is for releasing threads while accessing external resources), you can end up with strange results.
I would like to share a solution for an issue i saw in some comments.
If you're scared about thread rate limit, and you want to limit this by yourself, you can do something like this, using SemaphoreSlim.
var nbCores = Environment.ProcessorCount;
var semaphore = new SemaphoreSlim(nbCores, nbCores);
var processTasks = items.Select(async x =>
{
await semaphore.WaitAsync();
try
{
await ProcessAsync();
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(processTasks);
In this example, i called concurrently my "ProcessAsync" but limited to {processor number} concurrent processes.
Hope that's help someone.
NB : You could set the "nbCores" variable as a proper value that satisfy your code condition, of course.
NB 2 : This example is for some use cases, not all of them. I would highly suggest with a big load of task to refer to TPL programming

WebAPI HttpContext is Null Inside ContinueWith() => tast

I'm just wondering if someone could explain what is happening here.
Given this Post method on an API controller:
public HttpResponseMessage PostImage()
{
var request = HttpContext.Current.Request;
var c = SynchronizationContext.Current;
var result = new HttpResponseMessage(HttpStatusCode.OK);
if (Request.Content.IsMimeMultipartContent())
{
Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ContinueWith((task) =>
{
MultipartMemoryStreamProvider provider = task.Result;
foreach (HttpContent content in provider.Contents)
{
Stream stream = content.ReadAsStreamAsync().Result;
Image image = Image.FromStream(stream);
var uploadFileName = content.Headers.ContentDisposition.FileName;
var requestInside = HttpContext.Current.Request; // this is always null
string filePath = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["UserFilesRootDir"]), userprofile.UserCode);
//string[] headerValues = (string[])Request.Headers.GetValues("UniqueId");
string fileName = userprofile.UserCode + ".jpg";
string fullPath = Path.Combine(filePath, fileName);
image.Save(fullPath);
}
});
return result;
}
}
Why would var requestInside = HttpContext.Current.Request; be null?
I've checked all the relevant settings:
<compilation debug="true" targetFramework="4.5">
...
<httpRuntime targetFramework="4.5"
And SynchronizationContext.Current is the newer AspNetSynchronizationContext rather than LegacyAspNetSynchronizationContext.
I'm presuming at the moment that it's because I'm on a different thread, is this a correct assumption?
ContinueWith is not guaranteed to run on the same thread hence the synchronization context could be lost. You could change your call to specify to resume on the current thread with parameter TaskScheduler.Current. See this previous SO answer.
If you use await/async pattern it will automatically capture the current syncronization context on resume once an awaitable operation completes. This is done by resuming the operation on the same thread which is bound to that context. An added benefit, IMHO, is cleaner looking code.
You can change your code to this which uses that pattern. I have not made any other changes to it other than use async/await.
public async Task<HttpResponseMessage> PostImage()
{
var request = HttpContext.Current.Request;
var c = SynchronizationContext.Current;
var result = new HttpResponseMessage(HttpStatusCode.OK);
if (Request.Content.IsMimeMultipartContent())
{
MultipartMemoryStreamProvider provider = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider());
foreach (HttpContent content in provider.Contents)
{
Stream stream = await content.ReadAsStreamAsync();
Image image = Image.FromStream(stream);
var uploadFileName = content.Headers.ContentDisposition.FileName;
var requestInside = HttpContext.Current.Request; // this is always null
string filePath = Path.Combine(HostingEnvironment.MapPath(ConfigurationManager.AppSettings["UserFilesRootDir"]), userprofile.UserCode);
//string[] headerValues = (string[])Request.Headers.GetValues("UniqueId");
string fileName = userprofile.UserCode + ".jpg";
string fullPath = Path.Combine(filePath, fileName);
image.Save(fullPath);
}
}
return result;
}

Resources