DomainService not registered in AppService - aspnetboilerplate

I am trying to incorporate DomainService into my application, and tried to do it like the code below shows.
Here is the sample code for the manager:
namespace FlexSped.DefaultColors
{
public class DefaultColorManager : FlexSpedDomainServiceBase, IDefaultColorsManager
{
private readonly IRepository<DefaultColor> _defaultColorRepository;
public DefaultColorManager(IRepository<DefaultColor> defColorRep)
{
_defaultColorRepository = defColorRep;
}
public async Task Create(DefaultColor input)
{
await _defaultColorRepository.InsertAsync(input);
}
public Task Update(int id)
{
throw new NotImplementedException();
}
}
}
And this is the application service:
namespace FlexSped.DefaultColors
{
[AbpAuthorize(AppPermissions.Pages_Administration_DefaultColors)]
public class DefaultColorsAppService : FlexSpedAppServiceBase, IDefaultColorsAppService
{
private readonly IDefaultColorsManager _defaultColorManager;
private readonly IRepository<DefaultColor> _defaultColorRepository;
//private readonly IIocResolver _iocResolver;
public DefaultColorsAppService(IRepository<DefaultColor> defaultColorRepository, IDefaultColorsManager defColManager)
{
_defaultColorRepository = defaultColorRepository;
_defaultColorManager = defColManager;
//_iocResolver = iocResolver;
}
public async Task CreateOrEdit(CreateOrEditDefaultColorDto input)
{
if (input.Id == null)
{
await Create(input);
}
else
{
await Update(input);
}
}
[AbpAuthorize(AppPermissions.Pages_Administration_DefaultColors_Create)]
private async Task Create(CreateOrEditDefaultColorDto input)
{
DefaultColor dt = ObjectMapper.Map<DefaultColor>(input);
await _defaultColorManager.Create(dt);
}
}
}
All this produces this error:
'FlexSped.DefaultColors.DefaultColorsAppService' is waiting for the following dependencies:
- Service 'FlexSped.DefaultColors.IDefaultColorsManager' which was not registered.
Not sure what the problem is.I was following convention here.

ABPboiler is registering the services dependencies by name so your should match the implementation with definition. In your case:
IDefaultColors.IDefaultColorsManager should be IDefaultColors.IDefaultColorManager
or vice versa DefaultColorManager should be DefaultColorsManager.

Related

How to invoke async callbacks in IEnlistmentNotification implementation

I have scenario to pass async function as callback to my own resource manager(which implements IEnlistmentNotification interface), and need to invoke asynchronously in prepare method, but it works when invoke as synchronous way, is there any way to make it without wait or asynchronous, the wait producing the AggregatorException rather than my custom exception?
Resource Manager
public class ResourceManager : IEnlistmentNotification
{
private Func<Task>? _doWorkCallback;
public async Task EnlistAsync(Func<Task> doWorkCallback)
{
_doWorkCallback = doWorkCallback;
var transaction = Transaction.Current;
if (transaction != null)
{
await transaction.EnlistVolatileAsync(this, EnlistmentOptions.None).ConfigureAwait(false);
}
}
public void Prepare(PreparingEnlistment preparingEnlistment)
{
try
{
_doWorkCallback?.Invoke().Wait();
preparingEnlistment.Prepared();
}
catch
{
preparingEnlistment.ForceRollback();
}
}
public void Commit(Enlistment enlistment)
{
enlistment.Done();
}
public void Rollback(Enlistment enlistment)
{
enlistment.Done();
}
public void InDoubt(Enlistment enlistment)
{
enlistment.Done();
}
}
public static class TranscationExtensions
{
public static Task EnlistVolatileAsync(this Transaction transaction,
IEnlistmentNotification
enlistmentNotification,
EnlistmentOptions enlistmentOptions)
{
return Task.FromResult(transaction.EnlistVolatile
(enlistmentNotification,
enlistmentOptions));
}
}
Usage Code
public class Test
{
private async Task DoWork()
{
Thread.Sleep(1000);// considerer here my custom exception
await Task.CompletedTask;
}
public async Task TestMethod()
{
ResourceManager rm = new ResourceManager();
await rm.EnlistAsync(async () => await DoWork().ConfigureAwait(false)).ConfigureAwait(false);
}
}

how to fix Error No DataBase Provider when Everything is okay

When I want to Insert A New Object into the db bellow Error Occured:
No database provider has been configured for this DbContext
Services:
private IConfiguration config;
public Startup(IConfiguration config) => this.config = config;
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlServer().AddDbContext<DataContext>(options => options.UseSqlServer(config["ConnectionStrings:MainConnection"]));
services.AddMvc();
}
DataContext:
public class DataContext:DbContext
{
public DataContext() { }
public DataContext(DbContextOptions<DataContext> options) : base(options) { }
public DbSet<Request> Request { get; set; }
public DbSet<AdminAccept> AdminAccept { get; set; }
public DbSet<Payment> Payment { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.OnConfiguring(builder);
}
}
Insert command :
public async Task <int> SaveToStorageAsync()
{
using (DataContext context=new DataContext())
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
}
however migrations and database created succefully
I solved it finally.
everything is okay but use of using expression cause an error.(I wonder why)
to solving it first of all I removed a using and declare a DataContext as parameter:
public async Task<int> SaveToStorageAsync(DataContext context)
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
after it initiate constructor in the main controller :
DataContext context;
public HomeController(DataContext context)
{
this.context = context;
}
and finally call function by sending context as a parameter.
hopped you used in your scenarios and good luck
Since you register the DataContext with the constructor receiving a DbContextOptions<DataContext> option.You also need to pass that when you create a DataContext
var optionsBuilder = new DbContextOptionsBuilder<DataContext >();
optionsBuilder.UseSqlServer("Your connection string");
using (DataContext context = new DataContext (optionsBuilder.Options))
{
context.Request.Add(this);
return await context.SaveChangesAsync();
}
I suggest that you could use dbContext by DI in controller which is a more recommended way in asp.net core:
public class StudentsController : Controller
{
private readonly DataContext _context;
public StudentsController(DataContext context)
{
_context = context;
}
public async Task <int> SaveToStorageAsync()
{
_context.Request.Add(this);
return await context.SaveChangesAsync();
}
}
The two ways are included in below link:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#configuring-dbcontextoptions

Issue getting fault message from message context in Masstransit

I have an application that needs to intercept the current message consume context and extract a value that is defined in a base interface. That value is a tenant code that is eventually used in an EF database context.
I have a provider that takes a MassTransit ConsumerContext, and then using context.TryGetMessage(), extracts the tenant code, which is ultimately used to switch database contexts to a specific tenant database.
The issue lies in the MessageContextTenantProvider below. If a non-fault message is consumed then ConsumeContext<IBaseEvent> works fine. However if it is a fault, ConsumeContext<Fault<IBaseEvent>> doesn't work as expected.
Durring debugging I can see that the message context for a fault is ConsumeContext<Fault<IVerifyEvent>>, but why doesn't it work with a base interface as per the standard message? Of course, ConsumeContext<Fault<IVerifiedEvent>> works fine, but I have a lot of message types, and I don't want to have to define them all in that tenant provider.
Any ideas?
public interface ITenantProvider
{
string GetTenantCode();
}
public class MessageContextTenantProvider : ITenantProvider
{
private readonly ConsumeContext _consumeContext;
public MessageContextTenantProvider(ConsumeContext consumeContext)
{
_consumeContext = consumeContext;
}
public string GetTenantCode()
{
// get tenant from message context
if (_consumeContext.TryGetMessage(out ConsumeContext<IBaseEvent> baseEvent))
{
return baseEvent.Message.TenantCode; // <-- works for the non fault consumers
}
// get tenant from fault message context
if (_consumeContext.TryGetMessage<Fault<IBaseEvent>>(out var gebericFaultEvent))
{
return gebericFaultEvent.Message.Message.TenantCode; // <- doesn't work generically
}
// get tenant from fault message context (same as above)
if (_consumeContext.TryGetMessage(out ConsumeContext<Fault<IBaseEvent>> faultEvent))
{
return faultEvent.Message.Message.TenantCode; // <= generically doesn't work when using the base interface?
}
// get tenant from specific concrete fault class
if (_consumeContext.TryGetMessage(out ConsumeContext<Fault<IVerifiedEvent>> verifiedFaultEvent))
{
return verifiedFaultEvent.Message.Message.TenantCode; // <-- this works
}
// not able to extract tenant
return null;
}
}
public partial class VerificationDbContext
{
string connectionString;
public string ConnectionString
{
get
{
if (connectionString == null)
{
string tenantCode = _tenantProvider.GetTenantCode();
connectionString = _tenantConnectionManager.GetConnectionString(orgId);
}
return connectionString;
}
}
private readonly ITenantProvider _tenantProvider;
private readonly ITenantConnectionManager _tenantConnectionManager;
public VerificationDbContext(ITenantProvider tenantProvider, ITenantConnectionManager tenantConnectionManager)
{
_tenantProvider = tenantProvider;
_tenantConnectionManager = tenantConnectionManager;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (string.IsNullOrEmpty(this.ConnectionString))
{
optionsBuilder.UseSqlServer(#"Data Source=.\SQLEXPRESS;Initial Catalog=VerificationDb;Integrated Security=True")
.ConfigureWarnings((warningBuilder) => warningBuilder.Ignore(RelationalEventId.AmbientTransactionWarning));
}
else
{
optionsBuilder.UseSqlServer(this.ConnectionString)
.ConfigureWarnings((warningBuilder) => warningBuilder.Ignore(RelationalEventId.AmbientTransactionWarning));
}
}
}
public interface ITenantConnectionManager
{
string GetConnectionString(string tenantCode);
}
public class TenantConnectionManager : ITenantConnectionManager
{
private ITenantRepository _tenantRepository;
public TenantConnectionManager(ITenantRepository tenantRepository)
{
_tenantRepository = tenantRepository;
}
public string GetConnectionString(string tenantCode)
{
return _tenantRepository.GetByTenantCode(tenantCode).ConnectionString;
}
}
public interface IBaseEvent
{
string TenantCode { get; }
}
public interface IVerifiedEvent : IBaseEvent
{
string JobReference { get; }
}
public class VerifiedEventConsumer : IConsumer<IVerifiedEvent>
{
private readonly IVerifyCommand _verifyCommand;
private readonly ITenantProvider _tenantProvider;
public VerifiedEventConsumer(ITenantProvider tenantProvider, IVerifyCommand verifyCommand)
{
_verifyCommand = verifyCommand;
_tenantProvider = tenantProvider;
}
public async Task Consume(ConsumeContext<IVerifiedEvent> context)
{
await _verifyCommand.Execute(new VerifyRequest
{
JobReference = context.Message.JobReference,
TenantCode = context.Message.TenantCode
});
}
}
public class VerifiedEventFaultConsumer : IConsumer<Fault<IVerifiedEvent>>
{
private readonly IVerifyFaultCommand _verifyFaultCommand;
private readonly ITenantProvider _tenantProvider;
public CaseVerifiedEventFaultConsumer(ITenantProvider tenantProvider, IVerifyFaultCommand verifyFaultCommand)
{
_verifyFaultCommand = verifyFaultCommand;
_tenantProvider = tenantProvider;
}
public async Task Consume(ConsumeContext<Fault<ICaseVerifiedEvent>> context)
{
await _verifyFaultCommand.Execute(new VerifiedFaultRequest
{
JobReference = context.Message.Message.JobReference,
Exceptions = context.Message.Exceptions
});
}
}
I've solved the issue by using the GreenPipes TryGetPayload extension method:
public class MessageContextTenantProvider : ITenantProvider
{
private readonly ConsumeContext _consumeContext;
public MessageContextTenantProvider(ConsumeContext consumeContext)
{
_consumeContext = consumeContext;
}
public string GetTenantCode()
{
// get tenant from message context
if (_consumeContext.TryGetMessage(out ConsumeContext<IBaseEvent> baseEvent))
{
return baseEvent.Message.TenantCode;
}
// get account code from fault message context using Greenpipes
if (_consumeContext.TryGetPayload(out ConsumeContext<Fault<IBaseEvent>> payloadFaultEvent))
{
return payloadFaultEvent.Message.Message.TenantCode;
}
// not able to extract tenant
return null;
}
}

How to pass the user context details from from bot Controller to FormDialog

Bot Info
SDK Platform: .NET
Active Channels: Direct Line
Deployment Environment: Azure Bot Service
Question
How to pass user context details from from bot Controller to FormDialog?
Code Example
public virtual async Task < HttpResponseMessage > Post([FromBody] Activity activity) {
if (activity != null && activity.GetActivityType() == ActivityTypes.Message) {
await Conversation.SendAsync(activity, () => {
return Chain.From(() => FormDialog.FromForm(RequestOrder.BuildEnquiryForm));
});
} else {
HandleSystemMessage(activity);
}
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
public static IForm < RequestOrder > BuildEnquiryForm() {
return new FormBuilder < RequestOrder > ()
.Message("Hello {***Pass current user name?????****}Welcome to request bot!")
.Field(nameof(IsTermsAgreed))
.Field(nameof(ServiceRequired))
.AddRemainingFields()
.OnCompletion(ProcessParkingPermitRequest)
.Message("Thank you, I have submitted your request.")
.Build();
}
Fei Han answer is correct but using a static variable might lead to some unexpected error since all instances are sharing the same value. A better approach would be using the state of the form.
Request Order From
In your RequestOrder class you need to add a new member variable username.
public class RequestOrder
{
public string username;
/* Rest of your member variables */
}
The .Message method allows you to access the state of the form. You can get the username from the state of the form as below:
public static IForm < RequestOrder > BuildForm()
{
return new FormBuilder < RequestOrder > ()
.Message(async (state) => {
return new PromptAttribute($"Hi {state.username}, Welcome to request bot! ");
})
.Field(nameof(IsTermsAgreed))
.Field(nameof(ServiceRequired))
.AddRemainingFields()
.OnCompletion(ProcessParkingPermitRequest)
.Message("Thank you, I have submitted your request.")
.Build();
}
Root Dialog
In your root Dialog, before calling the BuildForm you need to create a new instance of your RequestOrder class and initialize username as the current user's name. Then pass your form to the BuildForm with option FormOptions.PromptInStart.
[Serializable]
public class RootDialog : IDialog<object>
{
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var form = new RequestOrder()
{
username = context.Activity.From.Id
};
var requestOrderform = new FormDialog<RequestOrder>(form, RequestOrder.BuildForm, FormOptions.PromptInStart);
context.Call<RequestOrder>(requestOrderform, SampleFormSubmitted);
}
private async Task SampleFormSubmitted(IDialogContext context, IAwaitable<SampleForm> result)
{
try
{
var query = await result;
context.Done(true);
}
catch (FormCanceledException<SampleForm> e)
{
string reply;
if (e.InnerException == null)
{
reply = $"You quit. Maybe you can fill some other time.";
}
else
{
reply = $"Something went wrong. Please try again.";
}
context.Done(true);
await context.PostAsync(reply);
}
}
}
This is what you get:
In following sample code, I define a constructor of SandwichOrder class with a string type parameter, then I call FormDialog as a child dialog from root dialog (not from Messages Controller directly) and pass user name as parameter, which works for me, you can refer to it.
In RootDialog:
[Serializable]
public class RootDialog : IDialog<object>
{
public Task StartAsync(IDialogContext context)
{
context.Wait(MessageReceivedAsync);
return Task.CompletedTask;
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var username = "Fei Han";
var myform = new Microsoft.Bot.Builder.FormFlow.FormDialog<SandwichOrder>(new SandwichOrder($"{username}"), SandwichOrder.BuildForm, Microsoft.Bot.Builder.FormFlow.FormOptions.PromptInStart, null);
context.Call<SandwichOrder>(myform, FormCompleteCallback);
}
private async Task FormCompleteCallback(IDialogContext context, IAwaitable<SandwichOrder> result)
{
await context.PostAsync($"The form is completed!");
context.Done(this);
}
}
In SandwichOrder class:
namespace BotFormFlowTest
{
public enum SandwichOptions
{
BLT, BlackForestHam, BuffaloChicken, ChickenAndBaconRanchMelt, ColdCutCombo, MeatballMarinara,
OvenRoastedChicken, RoastBeef, RotisserieStyleChicken, SpicyItalian, SteakAndCheese, SweetOnionTeriyaki, Tuna,
TurkeyBreast, Veggie
};
public enum LengthOptions { SixInch, FootLong };
public enum BreadOptions { NineGrainWheat, NineGrainHoneyOat, Italian, ItalianHerbsAndCheese, Flatbread };
public enum CheeseOptions { American, MontereyCheddar, Pepperjack };
public enum ToppingOptions
{
Avocado, BananaPeppers, Cucumbers, GreenBellPeppers, Jalapenos,
Lettuce, Olives, Pickles, RedOnion, Spinach, Tomatoes
};
public enum SauceOptions
{
ChipotleSouthwest, HoneyMustard, LightMayonnaise, RegularMayonnaise,
Mustard, Oil, Pepper, Ranch, SweetOnion, Vinegar
};
[Serializable]
public class SandwichOrder
{
public static string username = "User";
public SandwichOrder(string uname)
{
username = uname;
}
public SandwichOptions? Sandwich;
public LengthOptions? Length;
public BreadOptions? Bread;
public CheeseOptions? Cheese;
public List<ToppingOptions> Toppings;
public List<SauceOptions> Sauce;
public static IForm<SandwichOrder> BuildForm()
{
return new FormBuilder<SandwichOrder>()
.Message($"Hello {username}, Welcome to the simple sandwich order bot!")
.Build();
}
};
}
Test Result:

Scheduled tasks using Orchard CMS

I need to create a scheduled task using Orchard CMS.
I have a service method (let's say it loads some data from external sources), and I need to execute it every day at 8:00 AM.
I figured out I have to use IScheduledTaskHandler and IScheduledTaskManager... Does anyone know how to solve this problem? Some sample code will be appreciated.
In your IScheduledTaskHandler, you have to implement Process to provide your task implementation (I Advise you to put your implementation in another service class), and you have to register your task in the task manager. Once in the Handler constructor to register the first task, and then in the process implementation, to ensure that once a task was executed, the next one is scheduled.
Here is a sample:
public class MyTaskHandler : IScheduledTaskHandler
{
private const string TaskType = "MyTaskUniqueID";
private readonly IScheduledTaskManager _taskManager;
public ILogger Logger { get; set; }
public MyTaskHandler(IScheduledTaskManager taskManager)
{
_taskManager = taskManager;
Logger = NullLogger.Instance;
try
{
DateTime firstDate = //Set your first task date (utc).
ScheduleNextTask(firstDate);
}
catch(Exception e)
{
this.Logger.Error(e,e.Message);
}
}
public void Process(ScheduledTaskContext context)
{
if (context.Task.TaskType == TaskType)
{
try
{
//Do work (calling an IService for instance)
}
catch (Exception e)
{
this.Logger.Error(e, e.Message);
}
finally
{
DateTime nextTaskDate = //Your next date (utc).
this.ScheduleNextTask(nextTaskDate);
}
}
}
private void ScheduleNextTask(DateTime date)
{
if (date > DateTime.UtcNow )
{
var tasks = this._taskManager.GetTasks(TaskType);
if (tasks == null || tasks.Count() == 0)
this._taskManager.CreateTask(TaskType, date, null);
}
}
}
You should do the first scheduling with an implementation of IOrchardShellEvents rather than in the task constructor to avoid adding multiple tasks.
Here is an abstract DailyTaskHandler class you can implement :
Usage
public class MyTaskHandler : DailyTaskHandler {
private readonly IMyService _myService;
public MyTaskHandler(IMyService myService,
IDailyTasksScheduler dailyTasksScheduler) : base(dailyTasksScheduler) {
_myService = myService;
}
public override int Hour => base.Hour; // you can override default hour
public override void Process() => _myService.DoStuff();
}
Abstract daily task handler and scheduler
public abstract class DailyTaskHandler : IDailyTaskHandler, IScheduledTaskHandler {
private readonly IDailyTasksScheduler _dailyTasksScheduler;
protected DailyTaskHandler(IDailyTasksScheduler dailyTasksScheduler) {
_dailyTasksScheduler = dailyTasksScheduler;
Logger = NullLogger.Instance;
TaskType = GetType().FullName;
}
public ILogger Logger { get; set; }
public virtual int Hour { get; } = 1; // default scheduled hour of the day
public string TaskType { get; }
public void Process(ScheduledTaskContext context) {
if (context.Task.TaskType == TaskType) {
Logger.Information($"Process task: {TaskType}");
try {
Process();
}
catch (Exception e) {
Logger.Error(e, e.Message);
}
finally {
_dailyTasksScheduler.Schedule(this);
}
}
}
public abstract void Process();
}
public class DailyTasksStarter : IOrchardShellEvents {
private readonly IEnumerable<IDailyTaskHandler> _dailyTaskHandlers;
private readonly IDailyTasksScheduler _dailyTasksScheduler;
public DailyTasksStarter(
IEnumerable<IDailyTaskHandler> dailyTaskHandlers,
IDailyTasksScheduler dailyTasksScheduler) {
_dailyTaskHandlers = dailyTaskHandlers;
_dailyTasksScheduler = dailyTasksScheduler;
}
public void Activated() => _dailyTasksScheduler.Schedule(_dailyTaskHandlers);
public void Terminating() { }
}
public class DailyTasksScheduler : IDailyTasksScheduler {
private readonly IScheduledTaskManager _scheduledTaskManager;
public DailyTasksScheduler(IScheduledTaskManager scheduledTaskManager) {
_scheduledTaskManager = scheduledTaskManager;
}
public void Schedule(IDailyTaskHandler dailyTaskHandler) => Schedule(new IDailyTaskHandler[] { dailyTaskHandler });
public void Schedule(IEnumerable<IDailyTaskHandler> dailyTaskHandlers) {
DateTime nextDay = DateTime.UtcNow.AddDays(1);
foreach (var dailyTaskHandler in dailyTaskHandlers) {
DateTime nextTaskDate = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, dailyTaskHandler.Hour, 0, 0, DateTimeKind.Utc);
if (nextTaskDate > DateTime.UtcNow && _scheduledTaskManager.GetTasks(dailyTaskHandler.TaskType)?.Any() != true) {
_scheduledTaskManager.CreateTask(dailyTaskHandler.TaskType, nextTaskDate, null);
}
}
}
}
public interface IDailyTaskHandler : IDependency {
int Hour { get; }
string TaskType { get; }
}
public interface IDailyTasksScheduler : IDependency {
void Schedule(IDailyTaskHandler dailyTaskHandler);
void Schedule(IEnumerable<IDailyTaskHandler> dailyTaskHandlers);
}
You can avoid using a task scheduler class by having the schedule method and the IOrchardShellEvents implementation on your task handler class.

Resources