Injecting settings into service from appsettings.JSON - asp.net-core

I have a service which read the data from a queue (Rabbit MQ - ProduceQueue), takes action on the message and publishes the status on a separate status queue (Rabbit MQ - StatusQueue).
The issue I am facing is I am not able to instantiate the Producer and Consumer with separate settings when I resolve the service instance.
JSON Settings:
"RabbitMQConnection": {
"UserName": "guest",
"Password": "guest",
"HostName": "localhost",
"QueueName": "TaskExecutorPublisher",
"ExchangeName": "TaskProducerExchange",
"Port": "9090"
},
"RabbitMQStatusConnection": {
"UserName": "guest",
"Password": "guest",
"HostName": "localhost",
"QueueName": "SequenceStatusPublisher",
"ExchangeName": "StatusExchange",
"Port": "9091"
}
Program.cs:
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(app => { app.SetBasePath(Directory.GetCurrentDirectory()); app.AddJsonFile("appsettings.json"); })
.ConfigureServices((context, services) =>
{
//services.AddMvcCore();
//services.AddMvc();
services.AddLogging();
services.AddSingleton<IMQConsumer, RabbitMQConsumer>()
.AddOptions<IMQConnectionConfiguration>().Configure(options =>
{
options.HostName = context.Configuration["RabbitMQConnection:HostName"];
options.Port = Convert.ToInt32( context.Configuration["RabbitMQConnection:Port"]);
options.UserName = context.Configuration["RabbitMQConnection:UserName"];
options.Password = context.Configuration["RabbitMQConnection:Password"];
options.ExtensionProperties = new Dictionary<string, string>() {
{ "QueueName", context.Configuration["RabbitMQConnection:QueueName"] },
{ "ExchangeName",context. Configuration["RabbitMQConnection:ExchangeName"] }};
});
services.AddSingleton<IMQProducer, RabbitMQProducer>()
.AddOptions<IMQConnectionConfiguration>().Configure(options =>
{
options.HostName = context.Configuration["RabbitMQStatusConnection:HostName"];
options.Port = Convert.ToInt32(context.Configuration["RabbitMQStatusConnection:Port"]);
options.UserName = context.Configuration["RabbitMQStatusConnection:UserName"];
options.Password = context.Configuration["RabbitMQStatusConnection:Password"];
options.ExtensionProperties = new Dictionary<string, string>() {
{ "QueueName", context.Configuration["RabbitMQStatusConnection:QueueName"] },
{ "ExchangeName",context. Configuration["RabbitMQStatusConnection:ExchangeName"] }};
});
services.AddHostedService<ExecutorServiceAPI>();
services.AddSingleton<IMQConnectionConfiguration, ConnectionConfiguration>(option =>
{
var connectionConfig = new ConnectionConfiguration();
connectionConfig.HostName = context.Configuration["RabbitMQConnection:HostName"];
connectionConfig.Port = Convert.ToInt32(context.Configuration["RabbitMQConnection:Port"]);
connectionConfig.UserName = context.Configuration["RabbitMQConnection:UserName"];
connectionConfig.Password = context.Configuration["RabbitMQConnection:Password"];
connectionConfig.ExtensionProperties = new Dictionary<string, string>() {
{ "QueueName", context.Configuration["RabbitMQConnection:QueueName"] },
{ "ExchangeName",context. Configuration["RabbitMQConnection:ExchangeName"] }};
return connectionConfig;
});
}).UseWindowsService()
ExecutorService code :
public class ExecutorServiceAPI : IHostedService
{
private readonly ILogger _logger;
private IMQConsumer _consumerConnection;
private IMQProducer _producerConnection;
public ExecutorServiceAPI(ILogger<ExecutorServiceAPI> logger, IMQConsumer consumerConnection, IMQProducer producerConnection)
{
if (consumerConnection == null)
throw new ArgumentNullException(nameof(consumerConnection));
_logger = logger;
_consumerConnection = consumerConnection;
_producerConnection = producerConnection;
}
}

In appsettings.json:
"Settings": {
"RabbitMQConnection": {
"UserName": "guest",
"Password": "guest",
"HostName": "localhost",
"QueueName": "TaskExecutorPublisher",
"ExchangeName": "TaskProducerExchange",
"Port": "9090"
},
"RabbitMQStatusConnection": {
"UserName": "guest",
"Password": "guest",
"HostName": "localhost",
"QueueName": "SequenceStatusPublisher",
"ExchangeName": "StatusExchange",
"Port": "9091"
}
}
Settings:
public class Settings
{
public SettingProperties RabbitMQConnection { get; set; }
public SettingProperties RabbitMQStatusConnection { get; set; }
}
SettingProperties:
public class SettingProperties
{
public string UserName { get; set; }
public string Password { get; set; }
public string HostName { get; set; }
public string QueueName { get; set; }
public string ExchangeName { get; set; }
public string Port { get; set; }
}
In Progarm.cs (.net 6) , add below code:
builder.Services.Configure<Settings>(builder.Configuration.GetSection("Settings"));
Then in HomeController:
public class HomeController : Controller
{
private readonly Settings _MysettingsM;
public HomeController(IOptions<Settings> APPsettings)
{
_MysettingsM = APPsettings.Value;
}
public IActionResult Index()
{
var R1= _MysettingsM.RabbitMQConnection;
var R2 = _MysettingsM.RabbitMQStatusConnection;
return View();
}
}
result:

Related

System.ArgumentException: 'Id field is not correctly populated'

I am trying to implement Redis, I am sending a put request from Postman and getting error.
Controller:
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.Created, Type = typeof(Brand))]
public async Task<IActionResult> Update([FromBody] Brand brand)
{
try
{
await _brandCollection.UpdateAsync(brand);
return Ok();
}
catch (Exception ex)
{
throw ex;
}
}
Error:
System.ArgumentException: 'Id field is not correctly populated'
From redis desktop manager I have confirmed that Id exists in record
Postman:
{
"Id": 1,
"Name": "Xiaomi",
"IsRegistered": "Yes",
"About": "Mobile Brand",
"Countries": [
"Pakistan",
"India",
"China"
]
}
Brand model class:
[Document(StorageType = StorageType.Json, Prefixes = new[] { "Brand" })]
public class Brand
{
[Indexed] public int Id { get; set; }
[Indexed] public string? Name { get; set; }
[Indexed] public string? IsRegistered { get; set; }
[Indexed] public string? About { get; set; }
[Indexed] public List<string>? Countries { get; set; }
}
I have injected HostedService as well in Program.cs:
builder.Services.AddHostedService<IndexCreationService>();
IndexCreationService:
public class IndexCreationService : IHostedService
{
private readonly RedisConnectionProvider _provider;
public IndexCreationService(RedisConnectionProvider provider)
{
_provider = provider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await _provider.Connection.CreateIndexAsync(typeof(Person));
await _provider.Connection.CreateIndexAsync(typeof(Category));
await _provider.Connection.CreateIndexAsync(typeof(Brand));
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

Masstransit not consuming non MassTransit messages

I have to publish a message using Python and consume it using MassTransit (.Net core app).
To test, I created a Console Application to produce the messages using the Azure.ServiceBuss library.
The consumer is a MassTransit implementation of the ServiceBus.
When I send the message to the queue (using my console application), MassTransit is not able to consume it.
I am aware of the Interoperability and all the headers we must send in order to MassTransit consume the messages, but I am not able to make the consumer work.
The producer:
namespace MassTransit.MultipleBus.ServiceBus.Models.Commands
{
class Program
{
const string ServiceBusConnectionString = "connstring";
const string QueueName = "topic";
static IQueueClient queueClient;
public static async Task Main(string[] args)
{
queueClient = new QueueClient(ServiceBusConnectionString, QueueName);
// Send messages.
await SendMessagesAsync();
Console.WriteLine("ENVIOU");
Console.ReadKey();
await queueClient.CloseAsync();
}
private static async Task SendMessagesAsync()
{
try
{
while (true)
{
string messageBody = JsonConvert.SerializeObject(new EnviarExemploPocAzureServiceBusCommand(
NewId.NextGuid(),
NewId.NextGuid(),
new Proposta()
)
{
Headers = new Dictionary<string, object>() { },
Host = new HostInfo()
});
var message = new Message(Encoding.UTF8.GetBytes(messageBody));
Console.WriteLine($"Enviando mensagem: {messageBody}");
await queueClient.SendAsync(message);
Console.WriteLine("Enviado. Enviar outro?");
Console.ReadKey();
}
}
catch (Exception exception)
{
Console.WriteLine($"{DateTime.Now} :: Exception: {exception.Message}");
}
}
}
}
The class I'm sending:
namespace MassTransit.MultipleBus.ServiceBus.Models.Commands
{
public class EnviarExemploPocAzureServiceBusCommand
{
public EnviarExemploPocAzureServiceBusCommand(Guid msgId, Guid convId, Proposta msg)
{
MessageId = msgId.ToString();
ConversationId = convId.ToString();
MessageType = new[]
{
"urn:message:MassTransit.MultipleBus.ServiceBus.Models.Commands:Proposta"
};
Message = msg;
SourceAddress = "";
DestinationAddress = "sb://organization.servicebus.windows.net/topic";
}
public string DestinationAddress { get; set; }
public string MessageId { get; set; }
public string ConversationId { get; set; }
public string SourceAddress { get; set; }
public HostInfo Host { get; set; }
public IDictionary<string, object> Headers { get; set; }
public Proposta Message { get; set; }
public string[] MessageType { get; set; }
}
public class Proposta
{
public Proposta()
{
Nome = "TESTE 2";
AcaoId = 2;
Mensagem = "TESTE 2";
}
public string Nome { get; set; }
public int AcaoId { get; set; }
public string Mensagem { get; set; }
}
public class HostInfo
{
public HostInfo()
{
MachineName = "NOTEXXXXX";
ProcessName = "iisexpress";
ProcessId = 34188;
Assembly = "MassTransit.MultipleBus";
AssemblyVersion = "1.0.0.0";
FrameworkVersion = "3.1.5";
MassTransitVersion = "7.0.2.0";
OperatingSystemVersion = "Microsoft Windows NT 10.0.19041.0";
}
public string MachineName { get; set; }
public string ProcessName { get; set; }
public int ProcessId { get; set; }
public string Assembly { get; set; }
public string AssemblyVersion { get; set; }
public string FrameworkVersion { get; set; }
public string MassTransitVersion { get; set; }
public string OperatingSystemVersion { get; set; }
}
}
The message queued in ServiceBus:
{
"DestinationAddress": "sb://organization.servicebus.windows.net/topic",
"MessageId": "00010000-0faa-0009-6939-08d854e183aa",
"ConversationId": "00010000-0faa-0009-69f0-08d854e183aa",
"SourceAddress": "",
"Host": {
"MachineName": "NOTEXXXXX",
"ProcessName": "iisexpress",
"ProcessId": 32608,
"Assembly": "MassTransit.MultipleBus",
"AssemblyVersion": "1.0.0.0",
"FrameworkVersion": "3.1.5",
"MassTransitVersion": "7.0.2.0",
"OperatingSystemVersion": "Microsoft Windows NT 10.0.19041.0"
},
"Headers": {
},
"Message": {
"nome": "TESTE 2",
"acaoId": 2,
"mensagem": "TESTE 2"
},
"MessageType": [
"urn:message:MassTransit.MultipleBus.ServiceBus.Models.Commands:Proposta"
]
}
The consumer startup:
services.AddMassTransit<IAzureServiceBusService>(x =>
{
x.AddConsumer<EnviarExemploPocAzureServiceBusCommandHandler>();
x.UsingAzureServiceBus((context, cfg) =>
{
cfg.UseConcurrencyLimit(serviceBusSettings.AzureServiceBusSettings.ExemploAplicacaoPocA.ConcurrencyLimit);
cfg.Host("connString", h =>
{
h.OperationTimeout = TimeSpan.FromSeconds(serviceBusSettings.AzureServiceBusSettings.ExemploAplicacaoPocA.OperationTimeout);
h.TransportType = Microsoft.Azure.ServiceBus.TransportType.AmqpWebSockets;
});
cfg.UseServiceBusMessageScheduler();
});
});
services.AddMassTransitHostedService();
services.AddSettings(configuration);
The handler:
namespace MassTransit.MultipleBus.ServiceBus.Handlers.CommandHandlers
{
public class EnviarExemploPocAzureServiceBusCommandHandler : IConsumer<Proposta>
{
public async Task Consume(ConsumeContext<Proposta> context)
{
await Task.CompletedTask;
}
}
public class EnviarExemploPocAzureServiceBusFaultCommandHandler : IConsumer<Fault<EnviarExemploPocAzureServiceBusCommand>>
{
public async Task Consume(ConsumeContext<Fault<EnviarExemploPocAzureServiceBusCommand>> context)
{
await Task.CompletedTask;
}
}
}
When I send the message using MassTransit as well, the consumer works and the message is queued like:
{
"messageId": "00010000-0faa-0009-6497-08d854edbfe1",
"conversationId": "00010000-0faa-0009-3b83-08d854edbfe5",
"sourceAddress": "sb://organization.servicebus.windows.net/XXXX",
"destinationAddress": "sb://organization.servicebus.windows.net/topic",
"messageType": [
"urn:message:MassTransit.MultipleBus.ServiceBus.Models.Commands:Proposta"
],
"message": {
"nome": "TESTE DOIS",
"acaoId": 2,
"mensagem": "TESTE DOIS"
},
"sentTime": "2020-09-09T18:25:37.6127127Z",
"headers": {
"MT-Activity-Id": "|1e87ff49-4beb56732bfd4887.3."
},
"host": {
"machineName": "NOTEXXXXXX",
"processName": "iisexpress",
"processId": 37092,
"assembly": "MassTransit.MultipleBus",
"assemblyVersion": "1.0.0.0",
"frameworkVersion": "3.1.5",
"massTransitVersion": "7.0.2.0",
"operatingSystemVersion": "Microsoft Windows NT 10.0.19041.0"
}
}
What am I doing wrong?
The namespace seems to be correct, I did everything I found about it and I can't make it work.
Can someone help me?

ASP.NET core POST request fail

I have a model:
public class CoreGoal
{
[Key]
public long CoreGoalId { get; set; }
public string Title { get; set; }
public string Effect { get; set; }
public string Target_Audience { get; set; }
public string Infrastructure { get; set; }
public virtual ICollection<Benefit> Benefits { get; set; }
public virtual ICollection<Step> Steps { get; set; }
public virtual ICollection<Image> Images { get; set; }
public virtual ICollection<SubGoal> SubGoals { get; set; }
public CoreGoal()
{
}
}
And Image model is as following:
public class Image
{
[Key]
public long ImagelId { get; set; }
public byte[] Base64 { get; set; }
[ForeignKey("CoreGoalId")]
public long CoreGoalId { get; set; }
public Image()
{
}
}
My controller class:
[Route("api/[controller]")]
public class CoreGoalController : Controller
{
private readonly ICoreGoalRepository _coreGoalRepository;
//Controller
public CoreGoalController(ICoreGoalRepository coreGoalRepository) {
_coreGoalRepository = coreGoalRepository;
}
//Get methods
[HttpGet]
public IEnumerable<CoreGoal> GetAll()
{
return _coreGoalRepository.GetAllCoreGoals();
}
[HttpGet("{id}", Name = "GetCoreGoal")]
public IActionResult GetById(long id)
{
var item = _coreGoalRepository.Find(id);
if (item == null)
{
return NotFound();
}
return new ObjectResult(item);
}
//Create
[HttpPost]
public IActionResult Create([FromBody] CoreGoal item)
{
if (item == null)
{
return BadRequest();
}
_coreGoalRepository.CreateCoreGoal(item);
return CreatedAtRoute("GetCoreGoal", new { id = item.CoreGoalId }, item);
}
}
Repository:
public class CoreGoalRepository : ICoreGoalRepository
{
private readonly WebAPIDataContext _db;
public CoreGoalRepository(WebAPIDataContext db)
{
_db = db;
}
//Add new
public void CreateCoreGoal(CoreGoal coreGoal)
{
_db.CoreGoals.Add(coreGoal);
_db.SaveChanges();
}
//Get all
public IEnumerable<CoreGoal> GetAllCoreGoals()
{
return _db.CoreGoals
.Include(coreGoal => coreGoal.Benefits)
.Include(coreGoal => coreGoal.Steps)
.Include(coreGoal => coreGoal.Images)
.Include(coreGoal => coreGoal.SubGoals)
.ToList();
}
//Find specific
public CoreGoal Find(long key)
{
return _db.CoreGoals.FirstOrDefault(t => t.CoreGoalId == key);
}
}
public interface ICoreGoalRepository
{
void CreateCoreGoal(CoreGoal coreGoal);
IEnumerable<CoreGoal> GetAllCoreGoals();
CoreGoal Find(long key);
void DeleteCoreGoal(long id);
void UpdateCoreGoal(CoreGoal coreGoal);
}
When I do a POST request from swagger I get a template like:
{
"coreGoalId": 0,
"title": "string",
"effect": "string",
"target_Audience": "string",
"infrastructure": "string",
"benefits": [
{
"benefitId": 0,
"what": "string",
"coreGoalId": 0
}
],
"steps": [
{
"stepId": 0,
"what": "string",
"coreGoalId": 0
}
],
"images": [
{
"imagelId": 0,
"base64": "string",
"coreGoalId": 0
}
],
"subGoals": [
{
"subGoalId": 0,
"title": "string",
"priority": "string",
"audience": "string",
"social_aspects": "string",
"coreGoalId": 0,
"issues": [
{
"issueId": 0,
"title": "string",
"subGoalID": 0
}
]
}
]
}
If I POST like like this, my request fails with status 400, however if I remove
"images": [
{
"imagelId": 0,
"base64": "string",
"coreGoalId": 0
}
],
from this request, then it is successful. Why is it happening? All other models i.e. Benefit, Step are exactly identical to Image in structure.
UPDATE:
Changing base64 type from byte[] to string eliminates this problem but in that case while saving to my MySql database the big base64 string is chopped and kind of becomes useless to again form the image.

RavenDB UniqueConstraint doesn't seem to work

I've been trying for a day to get UniqueConstraint working, but it doesn't seem the are. I have a simple MVC6 site that creates a User on a POST. I'm expecting that on the second POST an exception should be thrown as a user will have already been created with the same properties. I'm wanting to ensure that the email address is unique.
using Raven.Client;
using Raven.Client.Document;
using Raven.Client.UniqueConstraints;
namespace MVC6Test.DomainModel
{
public class User
{
public string Id { get; private set; }
[UniqueConstraint]
public string Email { get; set; }
public string Password { get; set; }
public string Name { get; set; }
}
}
namespace MVC6Test.Web.Controllers
{
public class AdminController : Microsoft.AspNet.Mvc.Controller
{
private IDocumentStore _documentStore { get; set; }
public IDocumentSession Session { get; set; }
[HttpPost]
[AllowAnonymous]
[Route("login")]
public async Task<IActionResult> Login(string userName, string password)
{
User user = new User() {
Email = "test#gmail.com"
};
Session.Store(user);
}
public override void OnActionExecuting(ActionExecutingContext context)
{
if (_documentStore.IsDefault()) {
_documentStore = context.HttpContext.RequestServices.GetRequiredService<IDocumentStore>();
}
Session = _documentStore.OpenSession();
base.OnActionExecuting(context);
}
public override void OnActionExecuted(ActionExecutedContext context)
{
using (Session) {
if (Session != null && context.Exception == null) {
Session.SaveChanges();
}
}
base.OnActionExecuted(context);
}
}
}
namespace MVC6Test.Web
{
public class Startup
{
private IDocumentStore DocumentStore;
public void ConfigureServices(IServiceCollection services)
{
DocumentStore = new DocumentStore {
DefaultDatabase = "MVC6Test",
Url = "http://localhost:3366"
};
DocumentStore.Listeners.RegisterListener(new UniqueConstraintsStoreListener());
DocumentStore.Initialize();
services.TryAddSingleton(typeof(IDocumentStore), (provider) => {
return DocumentStore;
});
}
public void Configure(IApplicationBuilder app, IApplicationLifetime lifetime)
{
lifetime.ApplicationStopped.Register(() => {
DocumentStore.Dispose();
});
}
}
}
I do get this metadata on the items that are created:
{
"Raven-Entity-Name": "Users",
"Raven-Clr-Type": "MVC6Test.DomainModel.User, MVC6Test",
"Ensure-Unique-Constraints": [
{
"Name": "Email",
"CaseInsensitive": false
}
]
}

RavenDB query NOT contains

I have collection of documents Users
User
{
"Status": "ACTIVE",
"Login": {
"UserName": "login",
"Password": null,
"CreationDate": "2011-12-07T11:30:24.4062500Z",
"Roles": [
{
"Id": "roles/WebUser",
"Name": "WebUser"
},
{
"Id": "roles/Admin",
"Name": "Admin"
}
]
},
}
How can i make a query to get list of users with role name "WebUser" except users with role name "Admin" (Contains role "WebUser" but not contains role "Admin")
Using LINQ or lucene
You need to create an index for that, something like:
from user in docs.Users
select new { Roles = user.Logins.Roles.Select(x=>x.Name) }
And then you can query is using:
Roles:WebMaster AND -Roles:Admin
Is this what you want?
var users = documentSession.Query<User>()
.Where(x => x.Login.Roles.Any(y => y.Name == "WebUser"))
.Where(x => x.Login.Roles.Any(y => y.Name != "Admin"))
.ToList();
sample unit test....
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client;
using Raven.Client.Embedded;
using Raven.Client.Linq;
namespace Foo.Tests.
{
public class UserTests
{
[Test]
// ReSharper disable InconsistentNaming
public void GivenSomeUsersWithWebUserAndAdminRoles_Query_ReturnsSomeUsers()
// ReSharper restore InconsistentNaming
{
IDocumentStore documentStore;
using (documentStore = new EmbeddableDocumentStore {RunInMemory = true})
{
// Arrange.
documentStore.Initialize();
// Create and store Fake Data.
using (IDocumentSession documentSession = documentStore.OpenSession())
{
IEnumerable<User> users = CreateFakeUsers(documentSession);
foreach (var user in users)
{
documentSession.Store(user);
}
documentSession.SaveChanges();
}
using (IDocumentSession documentSession = documentStore.OpenSession())
{
// Act.
var users = documentSession.Query<User>()
.Where(x => x.Login.Roles.Any(y => y.Name == "WebUser"))
.Where(x => x.Login.Roles.Any(y => y.Name != "Admin"))
.ToList();
// Assert.
Assert.IsNotNull(users);
Assert.AreEqual(2, users.Count);
}
}
}
private IEnumerable<User> CreateFakeUsers(IDocumentSession documentSession)
{
return new List<User>
{
new User
{
Status = "ACTIVE",
Login = new Login
{
UserName = "loging",
Password = null,
CreationDate = DateTime.UtcNow,
Roles = new List<Role>
{
new Role
{
Id = "roles/WebUser",
Name = "WebUser"
},
new Role
{
Id = "roles/Admin",
Name = "Admin"
}
}
}
},
new User
{
Status = "ACTIVE",
Login = new Login
{
UserName = "User 2",
Password = null,
CreationDate = DateTime.UtcNow,
Roles = new List<Role>
{
new Role
{
Id = "roles/WebUser",
Name = "WebUser"
}
}
}
},
new User
{
Status = "INACTIVE",
Login = new Login
{
UserName = "User 3",
Password = null,
CreationDate = DateTime.UtcNow,
Roles = new List<Role>
{
new Role
{
Id = "roles/Admin",
Name = "Admin"
}
}
}
}
};
}
#region Nested type: Login
private class Login
{
public string UserName { get; set; }
public string Password { get; set; }
public DateTime CreationDate { get; set; }
public ICollection<Role> Roles { get; set; }
}
#endregion
#region Nested type: Role
private class Role
{
public string Id { get; set; }
public string Name { get; set; }
}
#endregion
#region Nested type: User
private class User
{
public string Id { get; set; }
public string Status { get; set; }
public Login Login { get; set; }
}
#endregion
}
}