Dynamic Web API Controller not created - aspnetboilerplate

i'm trying to add new IApplicationService on existing web application but ABP doesn't register that
here is my code
interface
public interface iElementAppService: IApplicationService
{
Task<long> CountElementsAsync();
}
implementation
public class GretaAppService : BBWP_ABP_MPA_EFAppServiceBase, iElementAppService
{
public Task<long> CountElementsAsync()
{
throw new NotImplementedException();
}
public GretaAppService()
{
}
all my other Dynamic web api controller is created except this one

the problem is solved by capitalizing the letters i of the iElementAppService interface to IElementAppService :(

Related

Unity IoC Not Registering Types Correctly

I have a well known issue where my Web API complains that my controller does not have a parameterless constructor. I have been through many pages and questions on this but cant seem to find the issue.
I installed Unity using Nuget command Install-Package Unity.WebAPI. The UnityConfig was created properly.
This is my UnityConfig file:
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IImportHeadService, ImportHeadService>();
container.RegisterType<IImportDetailService, ImportDetailService>();
container.RegisterType<ICurrencyService, CurrencyService>();
container.RegisterType<ISupplierService, SupplierService>();
container.RegisterType<IKPIService, KPIService>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
I then registered the UnityConfig in my Global.asax file as below:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
UnityConfig.RegisterComponents();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
And finally, here is my ImportController which is what I am trying to call through fiddler:
public class ImportController : ApiController
{
private IImportHeadService _importHeadService;
private IImportDetailService _importDetailService;
public ImportController(IImportHeadService importHeadService, IImportDetailService importDetailService)
{
_importHeadService = importHeadService;
_importDetailService = importDetailService;
}
[HttpGet, Route("api/Import/Info")]
public HttpResponseMessage GetInfo()
{
return Request.CreateResponse(HttpStatusCode.OK, "Import Tracker v1.0 - Import Controller");
}
}
As you can see it is a very simple controller at this point but I receive the following error:
An error occurred when trying to create a controller of type 'ImportController'. Make sure that the controller has a parameterless public constructor.
OK, so I was being a bit silly after all. My services have a parameter in their constructor for a context. Once I added the context into the Unity configuration. It all worked.

How to unit test an action filter attribute for web api in asp.net core?

I have written an action filter for a web api. If a method in the api controller throws an unhandled exception, then the filter creates an internal error 500 response.
I need to know how to test the filter?
I have researched extensively but could not create a suitable test. I tried context mocking, a service locator implementation and even an integration test using a test server.
The web api controller looks like this:
namespace Plod.Api.ApiControllers
{
[TypeFilter(typeof(UnhandledErrorFilterAttribute))]
[Route("api/[controller]")]
public class GamesController : BaseApiController
{
public GamesController(IGameService repository,
ILogger<GamesController> logger,
IGameFactory gameFactory
) : base(
repository,
logger,
gameFactory
)
{ }
// ..... controller methods are here
}
}
The complete controller is found here.
The filter is this:
namespace Plod.Api.Filters
{
public class UnhandledErrorFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.ExceptionHandled = true;
}
}
}
}
I even welcome changes to the filter implementation as a possible work around. Any help or ideas would be much appreciated. Thanks.
You probably can't. However, what you can do is spin up a TestServer and then hit it with a HttpClient. This really is an integration test and not a unit test. However, it's the good kind of integration test because it can be run safely in pipelines.
This document explains how to do this:
https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1
The issue you are going to face is that you will need to mock the underlying services inside your app. If you don't do that, your whole server will spin up and attempt to hit the database etc. Here is an example. This is using Moq. Incidentally I am sharing the ConfigureServices method with unit tests so they use the same object mesh of mocked services. You can still use the full functionality of Moq or NSubstitute to test the back-end (or even front -end).
I can hit my attributes in the test with breakpoint.
private void ConfigureServices(IServiceCollection services)
{
var hostBuilder = new WebHostBuilder();
hostBuilder.UseStartup<TestStartup>();
hostBuilder.ConfigureServices(services =>
{
ConfigureServices(services);
});
_testServer = new TestServer(hostBuilder);
_httpClient = _testServer.CreateClient();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_storageManagerFactory.Object);
services.AddSingleton(_blobReferenceManagerMock.Object);
services.AddSingleton(_ipActivitiesLoggerMocker.Object);
services.AddSingleton(_loggerFactoryMock.Object);
services.AddSingleton(_hashingService);
services.AddSingleton(_settingsServiceMock.Object);
services.AddSingleton(_ipActivitiesManager.Object);
services.AddSingleton(_restClientMock.Object);
_serviceProvider = services.BuildServiceProvider();
}
public class TestStartup
{
public void Configure(
IApplicationBuilder app,
ISettingsService settingsService)
{
app.Configure(settingsService.GetSettings());
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var mvc = services.AddMvc(option => option.EnableEndpointRouting = false);
mvc.AddApplicationPart(typeof(BlobController).Assembly);
services.AddSingleton(new Mock<IHttpContextAccessor>().Object);
return services.BuildServiceProvider();
}
}

Using FluentScheduler - ASP.NET Core MVC

I currently have a simple website setup with ASP.NET Core MVC (.NET 4.6.1), and I would like to periodically do some processes like automatically send emails at the end of every day to the registered members.
After doing some searching, I came across two common solutions - Quartz.NET and FluentScheduler.
Based on this SO thread, I found the approach of using FluentScheduler more easier to digest and use for my simple task. After quickly implementing the following lines of code into my Program.cs class, I had the emails going out successfully every minute (for testing purposes).
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
var registry = new Registry();
JobManager.Initialize(registry);
JobManager.AddJob(() => MyEmailService.SendEmail(), s => s
.ToRunEvery(1)
.Minutes());
host.Run();
}
}
However, now apart from sending emails I also need to do some back-end processing for e.g. updating the user records in the DB when mails are being sent out. For this, I normally inject my Entity Framework Context into the constructor of my controllers and use it to get/update SQL records.
My question is, since I cannot really inject these services into the main method, where would be the appropriate place to initialize the registry and add jobs for scheduling?
Thanks for the help, I am a little new to this so a little guidance would be much appreciated!
Instead of Program's Main function, I initialized the same in Startup.cs before app.UseMvc..
public void Configure(...., IDependencyObject dependencyObject)
{
....
JobManager.Initialize(new MyRegistry(dependencyObject));
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{controller}/{action}/{id?}");
});
}
My registry class looks like this:
public class MyRegistry: Registry
{
public MyRegistry(IDependencyObject dependencyObject)
{
Schedule(() => new SyncUpJob(dependencyObject)).ToRunNow().AndEvery(10).Seconds();
}
}
My Job class looks like this:
public class SyncUpJob: IJob
{
public SyncUpJob(IDependencyObject dependencyObject)
{
DependencyObject= dependencyObject;
}
public IDependencyObject DependencyObject{ get; set; }
public void Execute()
{
// call the method to run weekly here
}
}
You can define all your jobs and their schedules, by subclassing from FluentScheduler Registry class. something like:
public class JobRegistry : Registry {
public JobRegistry() {
Schedule<EmailJob>().ToRunEvery(1).Days();
Schedule<SomeOtherJob>().ToRunEvery(1).Seconds();
}
}
public class EmailJob : IJob {
public DbContext Context { get; } // we need this dependency, right?!
public EmailJob(DbContext context) //constructor injection
{
Context = context;
}
public void Execute()
{
//Job implementation code: send emails to users and update database
}
}
For injecting dependencies into jobs, you need to implement FluentScheduler IJobFactory interface. GetJobIntance method is called by FluentScheduler for creating job instances. Here you can use any DI library you want; In this sample implementation, I'm going to assume that you use Ninject:
public class MyNinjectModule : NinjectModule {
public override void Load()
{
Bind<DbContext>().To<MyDbContextImplemenation>();
}
}
public class JobFactory : IJobFactory {
private IKernel Kernel { get; }
public JobFactory(IKernel kernel)
{
Kernel = kernel;
}
public IJob GetJobInstance<T>() where T : IJob
{
return Kernel.Get<T>();
}
}
Now you can start your jobs in main method by calling:
JobManager.JobFactory = new JobFactory(new StandardKernel(new MyNinjectModule()));
JobManager.Initialize(new JobRegistry());

Spring repository without database but external api

We are building an API for our service and we would like to leverage Spring Data Rest as much as possible.
This API and the new model underneath will substitute a legacy API (and it's old model) that we still need to support.
Our idea is to build an "adapter" web app that replicates the structure of the old api and serve the old model using some internal transformations.
Also the old api is using Spring Data Rest, so here the idea:
build a repository implementation that instead of querying a database will query our brand new API, retrieve the new model, apply some transformations, and return the old model.
Unfortunately, even if I'm annotating the repository implementation with the #Repository annotation, Spring is not exposing the repository in the API.
I'm not sure if this is actually something possible to do or is just a matter of me not implementing some core functionalities.
What I would like to avoid is reimplement all spring data rest methods manually in a controller.
Here my Repository class
// Method are not implemented, this is just the backbone
#Repository
public class SampleRespositoryImpl implements ReadOnlyRepository<OldSample, String> {
NewApiClient client;
public SampleRespositoryImpl(NewApiClient client) {
this.client = client;
}
#Override
public OldSample findOne(String accession) {
NewSample newSample = client.fetch(accession)
OldSample oldSample = //apply transformation to newSample
return oldSample;
}
#Override
public boolean exists(String accession) {
return client.fetch(accession) != null;
}
#Override
public Iterable<OldSample> findAll() {
return new ArrayList<>();
}
#Override
public Iterable<OldSample> findAll(Iterable<String> var1) {
return new ArrayList<>();
}
#Override
public long count() {
return 0;
}
#Override
public Iterable<OldSample> findAll(Sort var1) {
return new ArrayList<>();
}
#Override
public Page<OldSample> findAll(Pageable var1) {
List<OldSample> OldSampleList = new ArrayList<>();
Page<OldSample> page = new PageImpl<>(OldSampleList);
return page;
}
}
Here what I would like to get back when I hit the api root (http://localhost:8080/)
{
"_links": {
"samples": {
"href": "http://localhost:8080/samples{?page,size,sort}
}
}
}
Someone else linked me to another answer in StackOverflow available here as possible duplication.
Reading through that answer, I decided that is too much effort to follow this path for our needs, so I'm more oriented to create a custom controller to expose necessary methods.
This solution was reported by Kevin as answer to Implementing methods of Spring Data repository and exposing them through REST

customizing odata output from asp.net web api

I'm using the new ASP.NET webapi odata (version 4.0.0 last published 27/2/2013 according to Nuget)
Basically I'm doing it as described here: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api
I'm publishing my data transfer objects and the odata atom pub feed is created but I'd like to have some more control over it. Mainly I'd like to be able to do the following:
decide what goes on the title, author and updated elements for the feed
decide whether or not to have the edit links
change what is shown in <category term="X"and in m:type in sub properties that are classes in my application. Currently they expose the c# class names with the full namespace but I don't want to expose this.
Thanks.
The OData media type formatter is more extensible now. Samples follow.
1) decide what goes on the title, author and updated elements for the feed
public class AtomMetadataFeedSerializer : ODataFeedSerializer
{
public AtomMetadataFeedSerializer(IEdmCollectionTypeReference edmType, ODataSerializerProvider serializerProvider)
: base(edmType, serializerProvider)
{
}
public override ODataFeed CreateODataFeed(IEnumerable feedInstance, ODataSerializerContext writeContext)
{
ODataFeed feed = base.CreateODataFeed(feedInstance, writeContext);
feed.Atom().Title = new AtomTextConstruct { Kind = AtomTextConstructKind.Text, Text = "My Awesome Feed" };
return feed;
}
}
public class CustomSerializerProvider : DefaultODataSerializerProvider
{
public override ODataEntrySerializer CreateEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsCollection() && edmType.AsCollection().ElementType().IsEntity())
{
// feed serializer
return new AtomMetadataFeedSerializer(edmType.AsCollection(), this);
}
return base.CreateEdmTypeSerializer(edmType);
}
}
And register the custom serializer provider using,
config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create(new CustomSerializerProvider(), new DefaultODataDeserializerProvider()));
2) customize edit links
public class CustomEntityTypeSerializer : ODataEntityTypeSerializer
{
public CustomEntityTypeSerializer(IEdmEntityTypeReference edmType, ODataSerializerProvider serializerProvider)
: base(edmType, serializerProvider)
{
}
public override ODataEntry CreateEntry(EntityInstanceContext entityInstanceContext, ODataSerializerContext writeContext)
{
ODataEntry entry = base.CreateEntry(entityInstanceContext, writeContext);
if (notProduceEditLinks)
{
entry.EditLink = null;
}
return entry;
}
}
public class CustomSerializerProvider : DefaultODataSerializerProvider
{
public override ODataEntrySerializer CreateEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsEntity())
{
// entity type serializer
return new CustomEntityTypeSerializer(edmType.AsEntity(), this);
}
return base.CreateEdmTypeSerializer(edmType);
}
}
and register the custom serializer provider as above.
We still don't support scenario 3 i.e aliasing type names and namespaces.

Resources