How can components communicate in real time in Blazor? - blazor-client-side

I've create a simple Singleton
public class SingletonService
{
public int Value { get; set; }
}
I registered it
private static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<SingletonService>();
}
I'm assigning it the value of the counter
#code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
singleton.Value = currentCount;
}
}
Here, I'm incrementing the value of the counter, but nothing is happening in other components
Only when I navigate to a different route that those values propagate to other components that are using the same services
Is that the correct behaviour? If so, I do I communicate in real time among components?
Thanks for helping

Related

Can multiple KafkaListener classes listen to the same topic?

I have kafka topic that contains multiple events (of different types), and I'd like to handle those events in different handler classes within single application. So my question is - can I create two classes(spring components) that consumes same topic, but each of them handles different events (from that same topic)?
#Component
#KafkaListener(topics = "topicA")
public class SomeClass {
#KafkaHandler
public void handleEventA(EventA eventA) {
}
}
#Component
#KafkaListener(topics = "topicA")
public class AnotherClass {
#KafkaHandler
public void handleEventB(EventB eventB) {
}
#KafkaHandler
public void handleEventC(EventC eventC) {
}
}
Normally you would have all the #KafkaHandlers in the same class.
You can do what you want, but each listener needs to be in a different consumer group and you need a default method to discard the events you are not interested in.
#Component
#KafkaListener(id = "some", topics = "topicA")
public class SomeClass {
#KafkaHandler
public void handleEventA(EventA eventA) {
}
#KafkaHandler(isDefault = true)
public void handleOthers(Object others) {
// discard
}
}
#Component
#KafkaListener(id = "another", topics = "topicA")
public class AnotherClass {
#KafkaHandler
public void handleEventB(EventB eventB) {
}
#KafkaHandler
public void handleEventC(EventC eventC) {
}
#KafkaHandler(isDefault = true)
public void handleOthers(Object others) {
// discard
}
}
Just share a finding after we tried this approach, the logic of listener container is executed per #KafkaListener class. i.e. the associated logic of FilterStrategy and MessageConverter will be run multiple times for the same event, which is probably not what we want.

Customizing the 'ApplicationUser' to hold more user data in ASP.NET Angular template (dotnet core 3.0)

I am currently working on an ASP.NET Web app with angular as a front end. As a base, the new template present in VisualStudio 2019 for ASP.NET angular, with Individual Authentication.
This run on dotnet core 3.0 Preview 4.
What I am trying to do is to add some user data to the default ApplicationUser.
Say my ApplicationUser is a student, I would like the student to be taking multiple classes, and each classes have multiple assignments.
ApplicationUser --> * Class --> * Assignment
To do so I have created the modes for the Class and Assignment and have added the relationships like so
example in ApplicationUser:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<Class> Classes { get; set; }
}
example in Class:
public class Class
{
public int ID { get; set; }
public string Name { get; set; }
public double CurrentGrade
{
get
{
if (Assignments.Count == 0)
{
return -1;
}
double grade = 0;
foreach (Assignment a in Assignments)
{
grade += (a.Weight * a.Score);
}
return grade;
}
}
public virtual ICollection<Assignment> Assignments { get; set; }
public Class()
{
Assignments = new List<Assignment>();
}
}
and example in Assignment:
public class Assignment
{
public int ID { get; set; }
public virtual Class FromClass { get; set; }
public string Name { get; set; }
public double Weight
{
get { return Weight; }
set
{
if (value <= 0 || value > 100)
{
throw new ArgumentException("The weight of the assignment should be between 0 and 100");
}
Weight = value;
}
}
public double Score
{
get { return Score; }
set
{
if (value <= 0 || value > 100)
{
throw new ArgumentException("The score of the assignment should be between 0 and 100");
}
Score = value;
}
}
public Assignment()
{
}
public Assignment(string name, double weight, double score)
{
this.Name = name;
this.Weight = weight;
this.Score = score;
}
}
This way I have added the virtual tags to define the relationships between the classes.
Finally, the ApplicationDbContext class was modified such that the tables for the new entities are generates (from my understanding)
public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser>
{
public virtual DbSet<Class> Classes { get; set; }
public virtual DbSet<Assignment> Assignments { get; set; }
public ApplicationDbContext(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Invoke the Identity version of this method to configure relationships
// in the AspNetIdentity models/tables
base.OnModelCreating(modelBuilder);
// Add a configuration for our new table. Choose one end of the relationship
// and tell it how it's supposed to work
modelBuilder.Entity<ApplicationUser>().HasMany(e => e.Classes); // ApplicationUser has many Classes
modelBuilder.Entity<Class>().HasMany(e => e.Assignments);
}
}
I believe that this is all that is needed achieve this but maybe something is missing.
My main issue now is the registration page. The template project already has the login and register functionality built in. I would like to modify the register page such that when a user registers, it can specify what classes it is currently signed in. Such that when its ApplicationUser is created and saved in the Identity table, the classes that the user (student) is taking are also created and saved in the database as well.
Template registration page that needs to be modified:
The issue is that in the template, the html/typescript files handling this are nowhere to be found. Would anyone know how I could go about modifying this page to fit the application? (It would also be nice to get rid of the 'User another service to register' generic text.)
You can override the default login pages by scaffolding the "Identity".
Right-click on your project in Solution Explorer and then select: Add->New Scaffolded Item->Identity
Then click Add. You can choose which pages you want to override (or just choose all). The pages will be created in the "Areas/Identity" folder.

Xamarin forms - Passing data between pages & views

I have a xamarin forms app.
There are 2 classes with data, one of the pages is filling the data.
The problem is: I'm creating new view, that should use data from both classes.
The only way i'm familiar with is to set a class as a bindingContext to pass data between pages, and it's working fine with ONE class, because apparently there couldn't be 2 bindingContext at the same time.
EXAMPLE:
1st class (all the classes are filled on the previous page. just accept that they are filled)
public class Buildings : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _id;
public string Id
{
get { return _id; }
set
{
_id = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Id"));
}
}
}
2nd class
public class Flats : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _num;
public string Num
{
get { return _num; }
set
{
_num = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Num"));
}
}
}
new view:
public partial class HouseView
{
private Flats _flats;
private Buildings _buildings;
public HouseView()
{
InitializeComponent();
}
private void HouseView_OnBindingContextChanged(object sender, EventArgs e)
{
var building = BindingContext as Building;
//var flat = BindingContext as Flat;
//_flat = flat;
_building = building;
var buildingInfo = await Rest.GetHouseInfo(_building.Id, _flat.Num); //function that will return info on a current house;
// rest code
}
}
Maybe there is no need for binding context, because i'm just passing the parameters, not changing them in a view? I guess the solution can be pretty simple, and i cant figure it out....
What you are missing is understanding the concept of ViewModel, and it's relation with the views.. In this case what you need is a 3rd class (ViewModel) that handles your 2 previous class:
public class HouseViewModel : INotifyPropertyChanged
{
public Flats Flats { get; set; }
private Buildings Buildings { get; set; }
}
Also using OnBindingContextChanged is just messy and will take some performance from your app .. try to prepare your data before on your VM, so the view knows as little as possible in how to get/handle data.
There is simple way to transfer data between pages in Xamarin forms.
Add new class to the main project called Transporter.cs, and this class should be static.
Inside this class, add the variables to transfer data between other pages; then you can simply access any variable by using Transporter.Variable.
Example:
public static Transporter
{
public static string x;
}
> Now, in each page, you can simply access (set or get) the value:
Transporter.x=MyName.Text;
>In another page:
MySecondName.Text=Transporter.x;
Note: MyName is an entry field in the first page, and MySecondName is an entry field in the second page.
Also, you can define any type of variables like (Lists, int, object... etc).

Design a class to be Unit testable

I am going though the Apress ASP.NET MVC 3 book and trying to ensure I create Unit Tests for everything possible but after spending a good part of a day trying to work out why edit's wouldn't save (see this SO question) I wanted to create a unit test for this.
I have worked out that I need to create a unit test for the following class:
public class EFProductRepository : IProductRepository {
private EFDbContext context = new EFDbContext();
public IQueryable<Product> Products {
get { return context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
context.Products.Add(product);
}
context.SaveChanges();
}
public void DeleteProduct(Product product) {
context.Products.Remove(product);
context.SaveChanges();
}
}
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
I am using Ninject.MVC3 and Moq and have created several unit tests before (while working though the previously mentioned book) so am slowly getting my head around it. I have already (hopefully correctly) created a constructor method to enable me to pass in _context:
public class EFProductRepository : IProductRepository {
private EFDbContext _context;
// constructor
public EFProductRepository(EFDbContext context) {
_context = context;
}
public IQueryable<Product> Products {
get { return _context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
_context.Products.Add(product);
} else {
_context.Entry(product).State = EntityState.Modified;
}
_context.SaveChanges();
}
public void DeleteProduct(Product product) {
_context.Products.Remove(product);
_context.SaveChanges();
}
}
BUT this is where I start to have trouble... I believe I need to create an Interface for EFDbContext (see below) so I can replace it with a mock repo for the tests BUT it is built on the class DbContext:
public class EFDbContext : DbContext {
public DbSet<Product> Products { get; set; }
}
from System.Data.Entity and I can't for the life of me work out how to create an interface for it... If I create the following interface I get errors due to lack of the method .SaveChanges() which is from the DbContext class and I can't build the interface using "DbContext" like the `EFDbContext is as it's a class not an interface...
using System;
using System.Data.Entity;
using SportsStore.Domain.Entities;
namespace SportsStore.Domain.Concrete {
interface IEFDbContext {
DbSet<Product> Products { get; set; }
}
}
The original Source can be got from the "Source Code/Downloads" on this page encase I have missed something in the above code fragments (or just ask and I will add it).
I have hit the limit of what I understand and no mater what I search for or read I can't seem to work out how I get past this. Please help!
The problem here is that you have not abstracted enough. The point of abstractions/interfaces is to define a contract that exposes behavior in a technology-agnostic way.
In other words, it is a good first step that you created an interface for the EFDbContext, but that interface is still tied to the concrete implementation - DbSet (DbSet).
The quick fix for this is to expose this property as IDbSet instead of DbSet. Ideally you expose something even more abstract like IQueryable (though this doesn't give you the Add() methods, etc.). The more abstract, the easier it is to mock.
Then, you're left with fulfilling the rest of the "contract" that you rely on - namely the SaveChanges() method.
Your updated code would look like this:
public class EFProductRepository : IProductRepository {
private IEFDbContext context;
public EFProductRepository(IEFDbContext context) {
this.context = context;
}
...
}
public interface IEFDbContext {
IDbSet<Product> Products { get; set; }
void SaveChanges();
}
BUT... the main question you have to ask is: what are you trying to test (conversely, what are you trying to mock out/avoid testing)? In other words: are you trying to validate how your application works when something is saved, or are you testing the actual saving.
If you're just testing how your application works and don't care about actually saving to the database, I'd consider mocking at a higher level - the IProductRepository. Then you're not hitting the database at all.
If you want to make sure that your objects actually get persisted to the database, then you should be hitting the DbContext and don't want to mock that part after all.
Personally, I consider both of those scenarios to be different - and equally important - and I write separate tests for each of them: one to test that my application does what it's supposed to do, and another to test that the database interaction works.
I guess your current code looks something like this (I put in the interface):
public class EFProductRepository : IProductRepository {
private IEFDbContext _context;
// constructor
public EFProductRepository(IEFDbContext context) {
_context = context;
}
public IQueryable<Product> Products {
get { return _context.Products; }
}
public void SaveProduct(Product product) {
if (product.ProductID == 0) {
_context.Products.Add(product);
} else {
_context.Entry(product).State = EntityState.Modified;
}
**_context.SaveChanges();**
}
public void DeleteProduct(Product product) {
_context.Products.Remove(product);
**_context.SaveChanges();**
}
}
public class EFDbContext : DbContext, IEFDbContext {
public DbSet<Product> Products { get; set; }
}
public interface IEFDbContext {
DbSet<Product> Products { get; set; }
}
The problem is EFProductRepository now expects an object implementing the IEFDbContext interface, but this interface does not define the SaveChanges method used at the lines I put between the asteriskes so the compiler starts complaining.
Defining the SaveChanges method on the IEFDbContext interface solves your problem:
public interface IEFDbContext {
DbSet<Product> Products { get; set; }
void SaveChanges();
}

Moq: Return mock object with most implementation created

I want to mock my Repository object in such a way that it can still do actual DB retrieve operations. Only for Saving operations, I wanted to setup to return mock data since I don't want it to save into the DB.
How should I do it?
Thanks.
Maybe you should make your Save operation virtual and override it in a subclass which you use in your tests rather than using Moq?
First of all, your unit tests should never actually go out to the database (it is all right for integration tests, but that is a larger topic). What you want to do is pretty straightforward with Moq, though:
public class MyRepo
{
public virtual string Save(MyClass foo)
{
// perform save...
}
}
public class MyService
{
public MyRepo Repo { get; set; }
public string VerifyAndSave(MyClass foo)
{
// verify foo...
return new Repo.Save(foo);
}
}
public class MyClass()
{
public string SomeData { get; set; }
}
Notice the virtual modifiers on the methods--these are important for Moq to be able to stub them.
In your tests you could then do something like this:
[TestClass]
public class SomeTests
{
private Mock<MyRepo> MockRepo { get; set; }
private MyService Target { get; set; }
[TestInitialize]
public void Setup()
{
MockRepo = new Mock<MyRepo>();
Target = new MyService();
Target.Repo = MockRepo.Object;
}
[TestMethod]
public void MyTest()
{
const string expectedOutput = "SAVED";
MyClass exampleData = new MyClass();
MockRepo.Setup(x => x.Save(It.IsAny<MyClass>())).Returns(expectedOutput);
Target.VerifyAndSave(exampleData);
MockRepo.Verify(x => x.Save(It.IsAny<MyClass>()));
}
}
The chained calls of Setup and Returns in this case would guarantee that the calling method (i.e. VerifyAndSave) would see the value that you specified--"SAVED" in this case.
For more examples, take a look at the Moq quickstart docs.

Resources