How to implement IStringLocalizer indexer with async method - c#

ASP.NET Core 5 MVC application gets translations in from table at runtime. EF Core async methods are used to implement IStringLocalizer interface.
The code shown below causes compile-time error:
The modifier 'async' is not valid for this item
on this line
public async LocalizedString this[string name] => new LocalizedString(name, await I(name));
How to implement IStringLocalizer interface using EF Core async data access?
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// Translation service.
/// Retrieves localized strings from database
/// </summary>
public sealed class Localizer : IStringLocalizer
{
readonly EevaContext ctx;
public Localizer(EevaContext ctx)
{
this.ctx = ctx;
}
async Task<string> I(string str)
{
return await ctx.Strings
.Where((s) => s.Est == estString.)
.SingleOrDefaultAsync();
}
#region interface implementation
public async LocalizedString this[string name] => new LocalizedString(name, await I(name));
public LocalizedString this[string name, params object[] arguments] => throw new NotImplementedException();
}
Answer in async Indexer in C# states that indexer can return Task . Maybe this can used.

Related

Understanding the code in an Abstract factory pattern

I am trying to learn design patterns in C# and my friend has written me some code for an Abstract factory pattern (I think).
from what I am seeing the code creates a factory(Fa),
this factory(Fa) then creates another factory(Fb) based on an Enum and then that factory(Fb) creates a concrete class that can be used to call an API etc.
I can create a factory(Fb) and it creates the class but when I call methods from the class that were created by the factory(fb), I do not see my methods and cant call them but can only call the class that it inherits.
What I am trying to do in a nutshell, is create a factory that creates Jane dolls (like it does) and this inherits everything from the doll class, it also has all its own properties, great, but why cant I access its own properties when I make a factory to create the Jane Factory, it only lets me use the inherited Doll methods this way, but if I created another factory to create Santa dolls it would have different methods I need to use.
**Web.Controllers
**
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Web.Controllers
{
public class InventoryController : Controller
{
private readonly IDollFactory _dollFactory;
private readonly IJaneDollFactory _janeDollFactory;
private readonly IMapper _mapper;
public InventoryController(IJaneDollFactory dollFactory, IMapper mapper, IDollFactory dollFactory1)
{
_janeDollFactory = dollFactory;
_mapper = mapper;
_dollFactory = dollFactory1;
}
public async Task<IActionResult> List()
{
var token = HttpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken);
var doll = _JaneDollFactory.Create(token, JaneScopeConstants.GetAllScopes());
var a = _DollFactory.Create(Doll.Jane, HttpContext);
var ab = await a.LGetProductAsync("TestProduct");
var inventory = await doll.GetInventory();
var ret = inventory.InventoryItems.Select(
inventoryItem => _mapper.Map<InventoryViewModel>(inventoryItem));
return View(ret);
}
}
}
DollFactory
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Web.Infrastructure;
public class DollFactory : IDollFactory
{
private readonly IJaneDollFactory _JaneDollFactory;
public DollFactory(IJaneDollFactory JaneDollFactory)
{
_JaneDollFactory = JaneDollFactory;
}
public IDoll Create(Doll Doll, HttpContext httpContext)
{
switch (Doll)
{
case Doll.Jane:
var token = httpContext.Session.GetObject<OAuthResponse>(SessionConstants.JaneToken);
return _JaneDollFactory.Create(token, JaneScopeConstants.GetAllScopes());
default:
throw new NotImplementedException();
}
}
}
IJaneDollFactory Interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Jane;
public interface IJaneDollFactory
{
IJaneDoll Create(OAuthResponse oAuthResponse, List<string> scopes, HttpMessageHandler httpMessageHandler = null);
}
**IJaneDoll interface **
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Jane;
public interface IJaneDoll : IDoll
{
//Inventory
Task<Inventory> GetInventory();
Task ListInventoryItem(InventoryItem product);
Task DeleteInventoryItem(string sku);
}
IDoll interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public interface IDoll
{
Task ListProductAsync(Product product);
Task<Product> GetProductAsync(string productId);
}
interface IDollFactory
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Web.Infrastructure;
public interface IDollFactory
{
IDoll Create(Doll doll, HttpContext httpContext);
}
JaneDollFactory
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Qqq.Dolls.Jane;
public class JaneDollFactory : IJaneDollFactory
{
private readonly IMapper _mapper;
private readonly JaneApiConfiguration _JaneApiConfiguration;
public JaneDollFactory(IOptions<JaneApiConfiguration> JaneApiConfiguration, IMapper mapper)
{
_mapper = mapper;
_JaneApiConfiguration = JaneApiConfiguration.Value;
}
public IJaneDoll Create(OAuthResponse oAuthResponse, List<string> scopes, HttpMessageHandler httpMessageHandler = null)
{
return new JaneDoll(_mapper, _JaneApiConfiguration, oAuthResponse, scopes, httpMessageHandler);
}
}
This is happening is because in you factory create method you have the return type as
IDoll
So when you create a doll, no matter what doll you instantiate, it gets implicitly casted into an IDoll (this is the mistake in DollFactory class)
Since your caller knows what doll it wants the abstract factory to create, when you retrieve the object you can explicitly cast it to an IJaneDoll
var a = (IJaneDoll) _DollFactory.Create(Doll.Jane, HttpContext);
This should allow you to access members from both IDoll and IJane doll.

ObservableCollection list is unable to find method AddRange

I am using Xamarin.Forms MVVM and sqlLite-net to make a Shared Mobile App.
I am getting an error bc 'AddRange' doesn't exist in ObservableCollection or I am using that function wrong.
All I want to do is to fill my ObservableCollection list. do I have to manually Add using loop? its weird ObservableCollection has a 'Add' method but no way to fill
Error: 'ObservableCollection' does not contain a definition for 'AddRange' and no accessible extension method 'AddRange' accepting a first argument of type 'ObservableCollection' could be found (are you missing a using directive or an assembly reference?)
using following refs:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using TestApp01_MVVM_Basic.Models;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
using System.Collections.Specialized;
using TestApp01_MVVM_Basic.Services;
using System.Collections.Generic;
using System.Linq;
Below I am creating my ObservableCollection. I am getting my error on line: AddRange()
public ObservableCollection<ProductModel> ProductsList { get; set; }
public ProductViewModel()
{
ProductsList = new ObservableCollection<ProductModel>();
}
public async Task MyDisplayList()
{
var getData = ProductService.DisplayProduct();
ProductsList.AddRange(getData);
}
In Servies Class, I have following DisplayProduct() method. that returns a list from database
public static async Task<IEnumerable<ProductModel>> DisplayProduct()
{
await Init();
var GetProduct = await db.Table<ProductModel>().ToListAsync();
return GetProduct;
}
What you are looking for is implemented on Xamarin community toolkit package: ObservableRangeCollection which sub-class System.Collections.ObjectModel.ObservableCollection<T>, you can use ObservableRangeCollection<ProductModel> instead of ObservableCollection<ProductModel> since the latter does not implement such method.
public ObservableRangeCollection<ProductModel> ProductsList { get; set; }
public ProductViewModel()
{
ProductsList = new ObservableRangeCollection<ProductModel>();
}
public async Task MyDisplayList()
{
var getData = await ProductService.DisplayProduct();
ProductsList.AddRange(getData);
}
public static async Task<IEnumerable<ProductModel>> DisplayProduct()
{
await Init();
var GetProduct = await db.Table<ProductModel>().ToListAsync();
return await Task.FromResult(GetProduct);
}

Activate Unit Test in Development and Test Phase and not Production phase

Goal:
Unit testing method TestMethod1 can only be used in development and test phase.
If it being used in production phase, everything will be canceled or similar.
Problem:
When I tried removing the string value "Development" from useEnvironment() method, the code is still working.
Is it possbile to activate the unit testing in development and test phase and not in production phase?
Info:
*Source code is taken from https://www.meziantou.net/testing-an-asp-net-core-application-using-testserver.htm
*Please take account that you might have about 500 unit test.
*Using asp.net core mvc v3
Thank you!
------
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using System.Net.Http;
using System.Threading.Tasks;
using Testtest;
namespace XUnitTestProject1.Test
{
/// <summary>
/// https://www.meziantou.net/testing-an-asp-net-core-application-using-testserver.htm
/// </summary>
public class Tests
{
[Fact]
public async Task TestMethod1()
{
var webHostBuilder =
new WebHostBuilder()
.UseEnvironment("Development") // You can set the environment you want (development, staging, production)
.UseStartup<Startup>(); // Startup class of your web app project
using (var server = new TestServer(webHostBuilder))
using (var client = server.CreateClient())
{
string result = await client.GetStringAsync("/api/values");
Assert.Equal("[\"value1\",\"value2\"]", result);
}
}
}
}
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Testtest.Controllers
{
/// <summary>
/// ValuesController
/// </summary>
[ApiController]
[Route("api/[controller]")]
public class ValuesController : Controller
{
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
}
Updated:
[CustomTestsFact]
[Fact]
public async Task TestMethod2()
{
using (var client = _server.CreateClient())
{
string result = await client.GetStringAsync("/api/values");
Assert.Equal("[\"value1\",\"value2\"]", result);
}
}
XUnit FactAttribute has Skip property that can be used to skip method.
You can create a custom class that will derive from FactAttribute and use your env variable to control whether the method should be skipped:
public class CustomFactAttribute : FactAttribute
{
public CustomTestsFactAttribute()
{
var phaseVariable = Environment.GetEnvironmentVariable("name of your env variable");
Skip = phaseVariable == "production"
? "Tests ignored"
: base.Skip;
}
}
And then you can mark your method with CustomFactAttribute:
[CustomTestsFact]
public async Task TestMethod1()
{
//your logic
}

AddAsync() method is missing

I am using Entity Framework Core. I want to create an async method which will create new user in my database, i have included all the libraries I need, but some methods that are supposed to work with database are missing, I have almost every async method but i am missing AddAsync and RemoveAsync. When I type AddAsync manually I get the following error message: "Error CS1061 'DbSet' does not contain a definition for 'AddAsync' and no accessible extension method 'AddAsync' accepting a first argument of type 'DbSet' could be found (are you missing a using directive or an assembly reference?)"
The class where the method is created has following code and libraries included:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
using System.Data;
using Microsoft.EntityFrameworkCore;
namespace ClassLibrary
{
public class Class1 : Interface1
{
public async Task AddKorisnik(Korisnici k)
{
using (ExtentEntities context = new ExtentEntities())
{
context.Korisnici.AddAsync();
await context.SaveChangesAsync();
}
}
}
}
The class where the DbContext is used is following:
namespace ClassLibrary
{
using System;
using System.Linq;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class ExtentEntities : DbContext
{
public ExtentEntities()
: base("name=ExtentEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Korisnici> Korisnici { get; set; }
}
}
There is nothing asynchronous with adding an object to an in-memory DbSet<T>. You should use the synchronous Add method to do this.
SaveChangesAsync() is the method that actually connects asynchronously to the underlying database.

Error activating Interface

I am new to .NET. I am create a internet shop but i have a problems
My Error:
Error activating IBookRepository No matching bindings are
available, and the type is not self-bindable. Activation path: 2)
Injection of dependency IBookRepository into parameter repo of
constructor of type BooksController 1) Request for BooksController
Suggestions: 1) Ensure that you have defined a binding for
IBookRepository. 2) If the binding was defined in a module, ensure
that the module has been loaded into the kernel. 3) Ensure you have
not accidentally created more than one kernel. 4) If you are using
constructor arguments, ensure that the parameter name matches the
constructors parameter name. 5) If you are using automatic module
loading, ensure the search path and filters are correct.
I using 3 project in Solution I have a interface IBookRepository in c# Class Library Domain and using asp.net mvc in controller
IBookRepository:
using Domain.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Domain.Abstract
{
public interface IBookRepository
{
IEnumerable<Book> Books { get; }
}
}
BooksController:
using Domain.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebUI.Controllers
{
public class BooksController : Controller
{
private IBookRepository repository;
public BooksController(IBookRepository repo)
{
repository = repo;
}
public ViewResult List()
{
return View(repository.Books);
}
}
}
I have a bindings for all the constructor parameter types:
private static void RegisterServices(IKernel kernel)
{
System.Web.Mvc.DependencyResolver.SetResolver(new WebUI.Infrastructure.NinjectDependencyResolver(kernel));
}
How can I fix this problem?
So you have the first step of dependency injection down, but you need to tell your code what concrete class to use when your interface is requested. To do that you need to create a binding for your concrete class.
To do this you need to navigate to your Ninject bindings file and add this:
Bind<IBookRepository>().To<NameOfYourClassThatImplementsIBookRepository>();
Obviously NameOfYourClassThatImplementsIBookRepository should be replaced with the actual name of your concrete class (i.e the class that implements your interface).
I am not aware of Ninject, but looking at the code above, BookController constructor needs an instance of class which implements IBookRepository. Think of constructor chaining or have one more default constructor to pass instance to above written constructor.
using Domain.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebUI.Controllers
{
public class BooksController : Controller
{
private IBookRepository repository;
public BooksController():this(new BookRepository())
{
}
public BooksController(IBookRepository repo)
{
repository = repo;
}
public ViewResult List()
{
return View(repository.Books);
}
}
}

Categories