MassTransit: publisher no longer work. Why? - masstransit

In previous project following code is working.
But now I need use MultiBus: - EventsConsumer located into current project. - Consumer for Payment is located in outter project.
Why this approach no longer work?
=================== Error:
Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: Publisher.Services.Abstract.IBusPublisher Lifetime: Singleton ImplementationType: Publisher.Services.Concrete.BusPublisher': Unable to resolve service for type 'MassTransit.IBus' while attempting to activate 'Publisher.Services.Concrete.BusPublisher'.
Inner Exception 2:
InvalidOperationException: Unable to resolve service for type 'MassTransit.IBus' while attempting to activate 'Publisher.Services.Concrete.BusPublisher'.
// =================== Startup
using System;
using MassTransit;
using MassTransit.MultiBus;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using CommonTypes.Options;
using Publisher.Consumers;
using Publisher.Services.Abstract;
using Publisher.Services.Concrete;
namespace Publisher
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public interface IEventsBus : IBus { }
public interface IPaymentBus : IBus { }
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Publisher", Version = "v1" });
});
#region MassTransit
services.AddSingleton<IBusPublisher, BusPublisher>();
services.Configure<EventsBusOptions>(Configuration.GetSection("EventsBusOptions"));
services.Configure<PaymentBusOptions>(Configuration.GetSection("PaymentBusOptions"));
services.AddScoped<EventsConsumer>();
// EventsConsumer located into current project
services.AddMassTransit<IEventsBus>(x =>
{
x.AddConsumer<EventsConsumer>();
x.UsingRabbitMq((context, cfg) =>
{
var _options = context.GetRequiredService<IOptions<EventsBusOptions>>().Value;
cfg.Host(new Uri(_options.HostUri), h =>
{
h.Username(_options.UserName);
h.Password(_options.Password);
});
cfg.ReceiveEndpoint(_options.QueueName, ep =>
{
ep.PrefetchCount = _options.PrefetchCount ?? 15;
ep.ConcurrentMessageLimit = _options.UseConcurrencyLimit ?? 16;
ep.ConfigureConsumer<EventsConsumer>(context);
});
cfg.ConfigureEndpoints(context);
});
});
// Consumer for Payment is located in outter project
// Did I properly describe Bus for outter consumer?
services.AddMassTransit<IPaymentBus>(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
var _options = context.GetRequiredService<IOptions<PaymentBusOptions>>().Value;
cfg.Host(new Uri(_options.HostUri), h =>
{
h.Username(_options.UserName);
h.Password(_options.Password);
});
cfg.ReceiveEndpoint(_options.QueueName, ep =>
{
ep.PrefetchCount = _options.PrefetchCount ?? 15;
ep.ConcurrentMessageLimit = _options.UseConcurrencyLimit ?? 16;
});
cfg.ConfigureEndpoints(context);
});
});
services.AddMassTransitHostedService();
services.AddGenericRequestClient();
#endregion
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Publisher v1"));
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
// =================== interface
using System.Threading.Tasks;
namespace Publisher.Services.Abstract
{
public interface IBusPublisher
{
Task Publish<Tin>(Tin request) where Tin : class;
Task<Tout> GetResponse<Tin, Tout>(Tin request) where Tin : class where Tout : class;
}
}
// =================== class
using System;
using MassTransit;
using System.Threading.Tasks;
using Publisher.Services.Abstract;
using Publisher.Contracts;
using Microsoft.Extensions.DependencyInjection;
namespace Publisher.Services.Concrete
{
public class BusPublisher : IBusPublisher
{
readonly IServiceProvider _provider;
readonly IBus _bus;
public BusPublisher(IServiceProvider provider, IBus bus)
{
_provider = provider;
_bus = bus;
}
public async Task Publish<Tin>(Tin request) where Tin : class
{
try
{
await _bus.Publish(request);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
public async Task<Tout> GetResponse<Tin, Tout>(Tin request)
where Tin : class
where Tout : class
{
try
{
using (var _scope = _provider.CreateScope())
{
var client = _scope.ServiceProvider.GetRequiredService<IRequestClient<Tin>>();
var response = await client.GetResponse<Tout>(request);
return response.Message;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
}

I have resolved my problem. And now I can publish message to EventsConsumer.
BUT I don't see mesages in 2nd bus queue (IPaymentBus).
Maybe I made some mistake. Plz help me to publish message in both queues.
//// ==================================== BusPublisher
namespace Publisher.Services.Concrete
{
public class BusPublisher : IBusPublisher
{
readonly IServiceProvider _provider;
readonly IPublishEndpoint _bus;
public BusPublisher(IServiceProvider provider, IPublishEndpoint bus)
{
_provider = provider;
_bus = bus;
}
public async Task Publish<Tin>(Tin request) where Tin : class
{
try
{
await _bus.Publish(request);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
public async Task<Tout> GetResponse<Tin, Tout>(Tin request)
where Tin : class
where Tout : class
{
try
{
using (var _scope = _provider.CreateScope())
{
var client = _scope.ServiceProvider.GetRequiredService<IRequestClient<Tin>>();
var response = await client.GetResponse<Tout>(request);
return response.Message;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
}
//// ==================================== Startup
namespace Publisher
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public interface IPaymentBus : IBus { }
public void ConfigureServices(IServiceCollection services)
{
....
#region MassTransit
services.Configure<EventsBusOptions>(Configuration.GetSection("EventsBusOptions"));
services.Configure<PaymentBusOptions>(Configuration.GetSection("PaymentBusOptions"));
services.AddScoped<EventsConsumer>();
services.AddScoped<IBusPublisher, BusPublisher>();
// EventsConsumer located into current project
//services.AddMassTransit<IEventsBus>(x =>
services.AddMassTransit(x =>
{
x.AddConsumer<EventsConsumer>();
x.UsingRabbitMq((context, cfg) =>
{
var _options = context.GetRequiredService<IOptions<EventsBusOptions>>().Value;
cfg.Host(new Uri(_options.HostUri), h =>
{
h.Username(_options.UserName);
h.Password(_options.Password);
});
cfg.ReceiveEndpoint(_options.QueueName, ep =>
{
ep.PrefetchCount = _options.PrefetchCount ?? 15;
ep.ConcurrentMessageLimit = _options.UseConcurrencyLimit ?? 16;
ep.ConfigureConsumer<EventsConsumer>(context);
});
cfg.ConfigureEndpoints(context);
});
});
// Consumer for Payment is located in outter project
// Did I properly describe Bus for outter consumer?
// I need just publish message to queue with _options.QueueName
services.AddMassTransit<IPaymentBus>(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
var _options = context.GetRequiredService<IOptions<PaymentBusOptions>>().Value;
cfg.Host(new Uri(_options.HostUri), h =>
{
h.Username(_options.UserName);
h.Password(_options.Password);
});
cfg.ReceiveEndpoint(_options.QueueName, ep =>
{
ep.PrefetchCount = _options.PrefetchCount ?? 15;
ep.ConcurrentMessageLimit = _options.UseConcurrencyLimit ?? 16;
});
cfg.ConfigureEndpoints(context);
});
});
services.AddMassTransitHostedService();
services.AddGenericRequestClient();
#endregion
}
}
}

Related

HttpContext.Session.GetString("string"), Randomly I get Session has not been configured for this application or request exception

Not everytime but some time i get error while i try to get HttpContext.Session.GetString("userid");
I am using .Net core 2.2
Below is my session helper code
public static class SessionHelper
{
private static HttpContext _context = null;
public static void SetCurrentContext(HttpContext context)
{
_context = context;
}
public static string UserID
{
get
{
try
{
return _context.Session.GetString("userid");
}
catch
{
return "";
}
}
set
{
_context.Session.SetString("userid", value);
}
}
}
Below in my middleware configuration in Configure method startup.cs
app.UseSession();
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Frame-Options", "sameorigin");
await next();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseMvcWithDefaultRoute();
Below is my ConfigureServices code of startup.cs
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(60 * 30);
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest;
//options.IOTimeout = TimeSpan.FromSeconds(60 * 30);
});
services.AddMvc()
.AddSessionStateTempDataProvider();

Call controller action from view in asp.net mvc core

I try to call a controller method from a view in asp.net core.
I have two different controller in my project. A Homecontroller and a controller for my Model Pupil.
From the navigation in the layout.cshtm I try to call the index method of my Pupilcontroller:
<a asp-action="Index" asp-controller="Pupil">Home</a>
I als tried #Html.Action("Pupil","Index","Pupil")
but nothing worked.
This is my Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using svkcore.Models;
namespace svkcore.Controllers
{
public class PupilController : Controller
{
private readonly SchuleContext _context;
public PupilController(SchuleContext context)
{
_context = context;
}
// GET: Pupil
public async Task<IActionResult> Index()
{
var schuleContext = _context.Pupils.Include(s => s.Ansprechpartner).Include(s => s.Fach);
return View(await schuleContext.ToListAsync());
}
// GET: Pupil/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var pupil= await _context.Pupils
.Include(s => s.Ansprechpartner)
.Include(s => s.Fach)
.FirstOrDefaultAsync(m => m.Idschueler == id);
if (pupil== null)
{
return NotFound();
}
return View(pupil);
}
// GET: Pupil/Create
public IActionResult Create()
{
ViewData["AnsprechpartnerId"] = new SelectList(_context.Ansprechpartners, "Idansprechpartner", "Adresse");
ViewData["FachId"] = new SelectList(_context.Faches, "Idfach", "Fach1");
return View();
}
// POST: Pupil/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Idschueler,Vorname,Nachname,AnsprechpartnerId,FachId,Klasse,Telefonnummer,Geburtstag")] Schueler schueler)
{
if (ModelState.IsValid)
{
_context.Add(pupil);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["AnsprechpartnerId"] = new SelectList(_context.Ansprechpartners, "Idansprechpartner", "Adresse", pupil.AnsprechpartnerId);
ViewData["FachId"] = new SelectList(_context.Faches, "Idfach", "Fach1", schueler.FachId);
return View(pupil);
}
// GET: Schueler/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var schueler = await _context.Pupils.FindAsync(id);
if (schueler == null)
{
return NotFound();
}
ViewData["AnsprechpartnerId"] = new SelectList(_context.Ansprechpartners, "Idansprechpartner", "Adresse", pupil.AnsprechpartnerId);
ViewData["FachId"] = new SelectList(_context.Faches, "Idfach", "Fach1", schueler.FachId);
return View(pupil);
}
// POST: Pupil/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Idschueler,Vorname,Nachname,AnsprechpartnerId,FachId,Klasse,Telefonnummer,Geburtstag")] Pupil pupil)
{
if (id != schueler.Idpupil)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(pupil);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!SchuelerExists(pupil.IdPupil))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
ViewData["AnsprechpartnerId"] = new SelectList(_context.Ansprechpartners, "Idansprechpartner", "Adresse", pupil.AnsprechpartnerId);
ViewData["FachId"] = new SelectList(_context.Faches, "Idfach", "Fach1", schueler.FachId);
return View(pupil);
}
// GET: Schueler/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var schueler = await _context.Pupils
.Include(s => s.Ansprechpartner)
.Include(s => s.Fach)
.FirstOrDefaultAsync(m => m.IdPupil == id);
if (Pupil== null)
{
return NotFound();
}
return View(Pupil);
}
// POST: Pupil/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var schueler = await _context.Pupils.FindAsync(id);
_context.Schuelers.Remove(pupil);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool PupilExists(int id)
{
return _context.Schuelers.Any(e => e.Idschueler == id);
}
}
}
the Routing in the Startup.cs:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
I always get this answer:
InvalidOperationException: Unable to resolve service for type 'svkcore.Models.SchuleContext' while attempting to activate 'svkcore.Controllers.SchuelerController'.
Can someone please give any advice, how to call a different controller from a link in a view?
Many thanks in advance!
Peter
#Startup-Class
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using svkcore.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace svkcore
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
Change ApplicationDbContext to SchuleContext
services.AddDbContext<SchuleContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
But, if you want the ApplicationDbContext to be injected also, have the the following configuration.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<SchuleContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));

How to use ActionFilter on Prometheus mapPath in standard .Net Web API?

I want to filter the range of client IPs who can route to Prometheus metrics.
So in startup I have
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.UsePrometheusServer(q =>
{
q.MapPath = "/metrics";
});
app.UseWebApi(config);
}
And this is my custom actionFilter class
public class IpFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
string clinetIP = GetClientIpAddress(actionContext.HttpContext.Items["MS_HttpRequestMessage"] as HttpRequestMessage);
if (IpAllowed(clinetIP))
base.OnActionExecuting(actionContext);
}
But I have no idea how to use IpFilter since it cannot be use as an attribute on a controller action.
I tried to use it by adding a middleware using owin but the next.Invoke doesn't work properly
public void Configuration(IAppBuilder app)
{
app.Map("/metrics", metricsApp =>
{
metricsApp.Use<TestIpMid>(deniedIps);
metricsApp.UsePrometheusServer(q => q.MapPath = "/metrics");
});
app.UsePrometheusServer(q =>
{
q.MapPath = "/metrics";
});
app.UseWebApi(config);
}
and this is the middleware:
public class TestIpMid : OwinMiddleware
{
private readonly HashSet<string> _deniedIps;
public TestIpMid(OwinMiddleware next, HashSet<string> deniedIps) : base(next)
{
_deniedIps = deniedIps;
}
public override async Task Invoke(IOwinContext context)
{
var ipAddress = context.Request.RemoteIpAddress;
if (_deniedIps.Contains(ipAddress))
{
context.Response.StatusCode = 403;
return;
}
await Next.Invoke(context);
}
}
please help me :'(
this solution worked for me but other ways I was thinking of didn't work
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var config = new HttpConfiguration();
var allowedIps = ProtectedSettings.Read(ProtectedSettings.protheusIpWhitelist).Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
app.Use(async (Context, next) =>
{
var ipAddress = Context.Request.RemoteIpAddress;
if ((!allowedIps.Contains(ipAddress)) && Context.Request.Path.Value == "/metrics")
{
Context.Response.StatusCode = 403;
return;
}
await next.Invoke();
});
app.UsePrometheusServer(q =>
{
q.MapPath = "/metrics";
});
app.UseWebApi(config);
}

JWT Token from postman never hits the controller with Authorize attribute

Trying to understand how JWT works for asp.net core application. I use a ASP.NET MVC Core application template.
My StartUp.cs cotains configuration for JWT Token :
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
//options.EventsType = typeof(AuthenticateCustomEvent);
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
And my login controller contains code to return token on successfull validation of the user this returns a token as shown below
Once i recieve the token i make a call to a controller with [Authorize] attribute applied to it with the bearer token from PostMan the controller never gets hit ? Am i missing something ?
My below solution is bit different, but this solution will help you to deal with custom auth implementation, you can implement a different type of auth for the different type of users. You require to create a class AuthorizationRequiredAttribute under your API project, this class will inherit ActionFilterAttribute class to filter each API request. you can filter all HTTP methods (GET, POST, PUT, DELETE...etc), and can implement your own authorization logic for specific HTTP method.
ActionFilterAttribute.cs
using BillSyatemCore.Common.Constants;
using BillSyatemCore.Services.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;
namespace BillSyatemCore.Handlers
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class AuthorizationRequiredAttribute : ActionFilterAttribute
{
private IConfiguration _config;
public AuthorizationRequiredAttribute(IConfiguration config)
{
_config = config;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
try
{
if (context.HttpContext.Request.Headers.ContainsKey(Constants.HttpHeaders.Token))
{
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(context.HttpContext.Request.Headers[Constants.HttpHeaders.Token])
as JwtSecurityToken;
var expireDate = Convert.ToDateTime(token.Claims.First(claim => claim.Type == Constants.JwtClaims.ExpiresOn).Value);
if (context.HttpContext.Request.Method == WebRequestMethods.Http.Get)
{
if (expireDate < DateTime.Now)
{
context.Result = new UnauthorizedResult();
}
}
else
{
//You may filter post,put,delete etc request here.
}
}
else
{
context.Result = new NotFoundResult();
}
}
catch (Exception ex)
{
context.Result = new BadRequestResult();
}
base.OnActionExecuting(context);
}
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//JWT
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build());
});
}
Controller.cs
using BillSyatemCore.Models.Authentication;
using BillSystemCore.Transporter;
using Microsoft.AspNetCore.Mvc;
namespace TestProject.Controllers
{
[Produces("application/json")]
[Route("api/[controller]")]
public class UserTypeController : Controller
{
private readonly IAuthTransporter _authTransporter;
public UserTypeController(IAuthTransporter authTransporter)
{
_authTransporter = authTransporter;
}
[HttpPost("save"), ServiceFilter(typeof(AuthorizationRequiredAttribute))]
public IActionResult Save([FromBody] UserType userType)
{
return Ok(_authTransporter.UserTypeServices.Save(userType));
}
}
}

MassTransit's ISendObserver is not observing

I have a consumer that is also publishing a response back to the bus. I can get an IReceiveObserver wired up and working on the bus, but I haven't been able to get either an ISendObserver or IPublishObserver running. I have confirmed with RabbitMQ management console that the messages are being published correctly.
class Program
{
static BusHandle _BusHandle;
static void Main(string[] args)
{
InitLogging();
InitStructureMap();
InitBus();
System.Console.WriteLine("Starting processing, ENTER to stop...");
System.Console.ReadLine();
System.Console.WriteLine("See you later, alligator!");
StopBus();
}
static void InitBus()
{
var busCtrl = ObjectFactory.Container.GetInstance<IBusControl>();
var recObserver = ObjectFactory.Container.GetInstance<IReceiveObserver>();
var sendObserver = ObjectFactory.Container.GetInstance<ISendObserver>();
busCtrl.ConnectReceiveObserver(recObserver);
busCtrl.ConnectSendObserver(sendObserver);
_BusHandle = busCtrl.Start();
}
static void StopBus()
{
_BusHandle.Stop();
}
static void InitLogging()
{
XmlConfigurator.Configure();
Log4NetLogger.Use();
}
static void InitStructureMap()
{
ObjectFactory.Initialize(x => {
x.AddRegistry<MyTestConsoleRegistry>();
x.AddRegistry<MyTestRegistry>();
});
}
}
public class MyTestConsoleRegistry : Registry
{
public MyTestConsoleRegistry()
{
var rabbitURI = ConfigurationManager.AppSettings["rabbitMQHostUri"];
var queueName = ConfigurationManager.AppSettings["massTransitQueue"];
For<IBusControl>(new SingletonLifecycle())
.Use("Configure IBusControl for MassTransit consumers with RabbitMQ transport",
ctx => Bus.Factory.CreateUsingRabbitMq(cfg => {
cfg.UseJsonSerializer();
cfg.PublisherConfirmation = true;
var host = cfg.Host(new Uri(rabbitURI), rabbitCfg => { });
cfg.ReceiveEndpoint(host, queueName, endpointCfg => {
endpointCfg.LoadFrom(ctx);
});
})
);
For<IReceiveObserver>().Use<MassTransitObserver>();
For<ISendObserver>().Use<MassTransitObserver>();
// ...snip...
}
}
public class MyTestRegistry : Registry
{
public MyTestRegistry()
{
ForConcreteType<MyTestConsumer>();
// ...snip...
}
}
public class MassTransitObserver : IReceiveObserver, ISendObserver
{
// Does nothing for now, just trying to wire it up...
public Task ConsumeFault<T>(ConsumeContext<T> context, TimeSpan duration, string consumerType, Exception exception) where T : class
{
return Task.CompletedTask;
}
public Task PostConsume<T>(ConsumeContext<T> context, TimeSpan duration, string consumerType) where T : class
{
return Task.CompletedTask;
}
public Task PostReceive(ReceiveContext context)
{
return Task.CompletedTask;
}
public Task PreReceive(ReceiveContext context)
{
return Task.CompletedTask;
}
public Task ReceiveFault(ReceiveContext context, Exception exception)
{
return Task.CompletedTask;
}
public Task PreSend<T>(SendContext<T> context) where T : class
{
return Task.CompletedTask;
}
public Task PostSend<T>(SendContext<T> context) where T : class
{
return Task.CompletedTask;
}
public Task SendFault<T>(SendContext<T> context, Exception exception) where T : class
{
return Task.CompletedTask;
}
}
public class MyTestConsumer : IConsumer<MyTestMessage>,
// for testing only:
IConsumer<MyTestResponse>
{
readonly IDoSomething _DoSomething;
public TestConsumer(IDoSomething doSomething)
{
_DoSomething = doSomething;
}
public Task Consume(ConsumeContext<MyTestResponse> context)
{
// For testing only...
return Task.CompletedTask;
}
public async Task Consume(ConsumeContext<MyTestMessage> context)
{
var result = await _DoSomething(context.Message.Id);
var resp = new MyTestResponseMessage(result);
await context
.Publish<MyTestResponse>(resp);
}
}
Given this code, the IReceiveObserver methods are getting called, but the ISendObserver methods are not.
I'm new to MassTransit, I expect this is probably a straightforward issue.
EDIT: A unit test using NUnit and Moq, doesn't use StructureMap. I believe this properly illustrates what I'm seeing.
[Test]
public void TestSendObserver()
{
var bus = CreateBus();
var busHandle = bus.Start();
var sendObs = new Mock<ISendObserver>();
sendObs.Setup(x => x.PreSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()))
.Returns(Task.FromResult(0))
.Verifiable();
sendObs.Setup(x => x.PostSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()))
.Returns(Task.FromResult(0))
.Verifiable();
using (bus.ConnectSendObserver(sendObs.Object)) {
var pubTask = bus.Publish(new TestMessage { Message = "Some test message" });
pubTask.Wait();
}
busHandle.Stop();
// Fails, neither PreSend nor PostSend have been called
sendObs.Verify(x => x.PreSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()), Times.Once());
sendObs.Verify(x => x.PostSend<TestMessage>(It.IsAny<SendContext<TestMessage>>()), Times.Once());
}
IBusControl CreateBus()
{
return MassTransit.Bus.Factory.CreateUsingRabbitMq(x => {
var host = x.Host(new Uri("rabbitmq://localhost/"), h => {
h.Username("guest");
h.Password("guest");
});
});
}
public class TestMessage
{
public String Message { get; set; }
}

Resources