I am trying out ABP 4.0 using the Blazor UI and want to override the built-in view for User Management.
Inspecting the source code I found the UserManagement.razor file which has the route of "/identity/users" - this matches the view that I want to override.
I have (I believe) followed the steps listed at: https://docs.abp.io/en/abp/latest/UI/Blazor/Customization-Overriding-Components. However when running the site, I still get the standard, built-in user list.
Pages/Identity/UserManagement.razor (within my wwwroot folder):
#inherits Volo.Abp.Identity.Blazor.Pages.Identity.UserManagement
<h2>This is not the standard page</h2>
Pages/Identity/UserManagement.razor.cs
using Volo.Abp.DependencyInjection;
namespace BlazorDemo.Blazor.Pages.Identity
{
[ExposeServices(typeof(UserManagement))]
[Dependency(ReplaceServices = true)]
public partial class UserManagement
{
}
}
Have I missed something here?
Use a diffent name for your own component, like MyUserManagement.razor. Otherwise, compoiler can not distinguish the classes. For example,
using Volo.Abp.DependencyInjection;
namespace BlazorDemo.Blazor.Pages.Identity
{
[ExposeServices(typeof(UserManagement))] //MUST BE Volo.Abp.Identity.Blazor.Pages.Identity.UserManagement
[Dependency(ReplaceServices = true)]
public partial class UserManagement
{
}
}
Here, ExposeServices exposes itself (your class) instead of the Volo.Abp.Identity.Blazor.Pages.Identity.UserManagement. If you rename your component to MyUserManagement than you don't make such mistakes :)
Related
I'm testing localization in Nancy and able to get it to work using EMBEDDED resource files but the issue is I don't want embedded resource files because I want them to be allowed to be edited via the GUI or using the file (if I go the DB route or setting the resource file as "content").
According to the doucmentation you should be able to override it to support using a database but I'm unable to get this to work (https://github.com/NancyFx/Nancy/wiki/Localization):
public class ResourceManager : ResourceBasedTextResource
{
public ResourceManager(IResourceAssemblyProvider resourceAssemblyProvider) : base(resourceAssemblyProvider)
{
}
public new string this[string key, NancyContext context]
{
get
{
return "HELO!";
}
}
}
This was just me messing around but I was hoping in the Razor view when I did #Text.Localization. it should return "HELO!" for everything... however it is not working
There really isn't a question in your post so I'm going to have to guess a bit and assume that you're not getting any exception but rather you're not seeing the "HELO!" in your view
Simply implementing a new ResourceBasedTextResource class is not enough. This is a core component and as such you are going to explicitly have to tell Nancy to use it. You do this by overriding the InternalConfiguration property of your Bootstrapper and tell Nancy to use your implementation instead
You can see it in the DemoBootstrapper of the demo that is linked from that wiki page https://github.com/NancyFx/Nancy/blob/8970ac9d6c7cf46e6060f0b83117c19fa18085c2/src/Nancy.Demo.Razor.Localization/DemoBootstrapper.cs#L11
Also, if you are not going to use resource files, then you should look into inheriting from ITextResource interface instead. It's a simple interface so it should be straight forward.
HTH
I am building a client/server solution, using an AngularJS Single Page App as the client component and a Self-Host ServiceStack RESTful API as the server component. A single Visual Studio Console Application Project holds HTML and JavaScript files for the AngularJS component, along with C# classes for bootstrapping the ServiceStack AppHost (I have devolved Interface and Service responsibilities to separate Visual Studio Projects).
I have set all HTML and JavaScript files to have a 'Build Action' of 'None' and a 'Copy to Output Directory' of 'Copy if newer'.
Everything is working very well as long as I am prepared to put up with having a '#' in my site URLs. I would like to eliminate this by using HTML5 pushstate URLs.
Effectively this means I need to persuade ServiceStack to serve up my default Single Page App HTML shell page whenever a non-existent route is requested. There is now a FallbackRoute attribute available in ServiceStack which appears to have been added exactly for this purpose.
However, I am unsure how to use it. I have found people asking similar questions here, here and here. But the answers given were all before the new FallbackRoute attribute arrived.
Essentially, I am looking for a simple, yet complete example of how to use the FallbackRoute attribute to ensure any requests to non-existent routes are redirected to a single static HTML page.
The RazorRockstars.Web has an implementation. I'll modify it to use a wildcard path and a default view:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
public string PathInfo { get; set; }
}
public class RockstarsService : Service
{
[DefaultView("Index")]
public object Any(Fallback request)
{
request.PathInfo = base.Request.PathInfo;
return request;
}
// ...
}
Since this is a service it requires a View page (details here) rather than a content page.
In the RockStars example, I can't determine what view would be rendered for the FallBackResponse, but setting the view explicitly should be all you need.
The [DefaultView("Index")] attribute I added to the Any method maps the response to a Views/Index.cshtml file. The Index.cshtml file can be empty but for a template declaration, and the complete markup for your single page app can be in your template file (i.e. _Layout.cshtml)
Without Razor
Read the html into a string and return it, while setting the content type to "text/html" with an attribute, see wiki docs on service return types
public class RockstarsService : Service
{
static string readContents;
[AddHeader(ContentType = "text/html")]
public string Any(Fallback request)
{
// check timestamp for changes for production use
if (readContents == '') {
using (StreamReader streamReader = new StreamReader(pathFromConfigFile, Encoding.UTF8))
{
readContents = streamReader.ReadToEnd();
}
}
return readContents;
}
// ...
}
It turns out it is all very simple with the FallbackRoute functionality, once you work out how to use it properly:
[FallbackRoute("/{Path*}")]
public class Fallback
{
public string Path { get; set; }
}
public class FallBackService : Service
{
public object Any(Fallback request)
{
return new HttpResult(new FileInfo("index.html")) {ContentType = "text/html"};
}
}
Once this is in place, I find 'index.html' is indeed getting served up whenever I try to hit a non-existent route.
Any static files, such as JavaScript and CSS resources, get served up as normal (as long as they have a 'Copy to Output Directory' setting of 'Copy if newer', of course).
This works like a charm with the HTML5 Push-state functionality in AngularJS.
I've been reading through a lot of the Jabbr code to learn Nancy and trying to implement many of the same patterns in my own application. One of the things I can't seem to get working is the concept of an on application start class. The Jabbr code base has an App_Start folder with a Startup.cs file (here) in it with the following implementation.
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
...
SetupNancy(kernel, app);
...
}
}
private static void SetupNancy(IKernel kernel, IAppBuilder app)
{
var bootstrapper = new JabbRNinjectNancyBootstrapper(kernel);
app.UseNancy(bootstrapper);
}
When I tried to do something similar to that in my project the Startup.cs file was just ignored. I searched the Jabbr code base to see if it was used anywhere but I wasn't able to find anything and the only differences I could see is Jabbr uses Ninject while I wanted to use AutoFac
Is there a way to register a startup class in nancy?
Take a look at my project over on GitHub, you'll be interested in the Spike branch and may have to unload the ChainLink.Web project to run I can't remember.
I had some trouble finding a way to configure the ILifetimeScope even after reading the accepted answer here by TheCodeJunkie. Here's how you do the actual configuration:
In the bootstrapper class derived from the AutofacNancyBootstrapper, to actually configure the request container, you update the ILifetimeScope's component registry.
protected override void ConfigureRequestContainer(
ILifetimeScope container, NancyContext context)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.Update(container.ComponentRegistry);
}
The application container can be updated similarly in the ConfigureApplicationContainer override.
You should install the Nancy.Bootstrappers.Autofac nuget, inherit from the AutofacNancyBootstrapper type and override the appropriate method (depending on your lifetime scope requirements: application or request). For more info check the readme file https://github.com/nancyfx/nancy.bootstrappers.autofac
HTH
After following the advice from TheCodeJunkie you can use the Update method on the ILifetimeScope container parameter which gives you a ContainerBuilder through an Action:
protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context)
{
container.Update(builder =>
{
builder.RegisterType<MyType>();
});
}
You cannot vote on your own post
0
Hi.
I am developing this (http://arg-co.com/SabteNam%20-%20Copy.zip) windows application, and for my DAL I use Entity Framework. But every single extension has its own EntityTypeConfiguration, so I decided to use [Import] and [Export] to add them in OnModelCreating method of my DbContext.The problem here is that, in 'SabteNamDbContext' class which is located on 'SabteNamDataAccess' library, the '_Configs' is not initialized so I cant iterate it and add its items to 'modelBuilder.Configurations'.
In the source code of 'SampleConfiguration' class, I commented out '[Export(typeof(IDbConfiguration))]' but even Uncommenting this part of code, do not cause application to work properly.
Intresting point is that, if I use the following code in 'Main' windows form, the '_Configs' would be initialized :
[ImportMany(typeof(IDbConfiguration))]
public IEnumerable<EntityTypeConfiguration<object>> _Configs { get; set; }
How can this be fixed ?
While I realize this is probably no longer of use to you, we use a variation on this model from OdeToCode, which I advise you read.
In our case, we have created an interface for our extensions in general, not just for the entity configuration like Scott did, which allows us not only to load the configurations, but also factory and test data per extension, add new permission types to the core application, etc.
Our OnModelCreating looks something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// load core object mappings
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new PermissionConfiguration());
// get plugin assemblies
var catalog = new DirectoryCatalog("bin");
var container = new CompositionContainer(catalog);
container.ComposeParts();
var plugins = container.GetExportedValues<IPlugin>();
// load plugin object mappings
foreach (IPlugin plugin in plugins)
{
plugin.RegisterDomainEntities(modelBuilder.Configurations);
}
base.OnModelCreating(modelBuilder);
}
Up until this point, I have been learning IoC/DI with Castle.Windsor using ASP.NET MVC, but I have a side project that is being done in Windows Forms, and I was wondering if there is an effective way to use it for that.
My problem is in the creation of forms, services, etc. In ASP.NET MVC, there is a sort of 'Activator' that does this under the hood, but this isn't the case in Windows Forms. I have to create a new Form like var form = new fclsMain();, so a Form like ..
class fclsMain : System.Windows.Forms.Form
{
private readonly ISomeRepository<SomeClass> someRepository;
fclsMain(ISomeRepository<SomeClass> someRepository)
{
this.someRepository = someRepository;
}
}
Falls kind of short. I would basically have to do ...
var form = new fclsMain(IoC.Resolve<ISomeRepository<SomeClass>);
Which as I have had pointed out in at least three of my questions isn't smart, because it's supposedly not the 'correct' usage of IoC.
So how do I work with Castle.Windsor and Windows Forms? Is there some way to design a Form Activator or something? I'm really lost, if I can't make a static IoC container that I can resolve from, what can I do?
Here you are doing something that are not very "Dependency Injection"...
var form = new fclsMain(IoC.Resolve<ISomeRepository<SomeClass>);
The "new" is the problem...
You have to call
var form = IoC.Resolve<fcls>();
the form of type fcls must be correctly configured via Fluent Registration API o
In order to use the same Castle container throughout your entire application, create a static class like:
public static class CastleContainer {
private static IWindsorContainer container;
public static IWindsorContainer Instance {
get {
if (container == null) {
container = new WindsorContainer();
}
return container;
}
// exposing a setter alleviates some common component testing problems
set { container = value; }
}
// shortcut to make your life easier :)
public static T Resolve<T>() {
return Instance.Resolve<T>();
}
public static void Dispose() {
if (container != null)
container.Dispose();
container = null;
}
}
Then register/install all your components in the Main() method. You can also hook into the application shutdown event to call Dispose() (although this isn't critical).
Castle actually uses a Windows Forms app in their quick-start guide.
Edit:
The pattern I showed above is a variant of the service locator, which some people refer to as an anti-pattern. It has a bad reputation because, among other reasons, it liters your code base with references to Windsor. Ideally, you should only have a single call to container.Resolve<...>() to create your root form. All other services & forms are injected via constructors.
Realistically, you'll probably need a few more calls to Resolve, especially if you don't want to load every single corner of the application at startup. In the web world, the best practice is to hand off the container to the web framework. In the Windows Forms world you'll need to implement your own service locator, like above. (Yes, handing the container to the ASP.NET MVC framework is still a service locator pattern).
I've edited the above code example so that the static container is injectable; no resources are tied up in a static context. If you do end up creating your own service locator, you might also want to create a test utility like this one to make testing easier.
public static class TestUtilities
{
public static IContainer CreateContainer(Action<IContainer> extraConfig = null)
{
var container = new WindsorContainer();
// 1. Setup common mocks to override prod configuration
// 2. Setup specific mocks, when provided
if (extraConfig != null)
extraConfig(container);
// 3. Configure container with production installers
CastleContainer.Instance = container;
return container;
}
}
This makes a shortcut for creating a new container that looks a lot like the production version, but with some services replaced with mocks. Some example tests might look like:
[Test]
public void SubComponentWorksGreat()
{
using (var container = TestUtilities.CreateContainer())
{
var subComponent = container.Resolve<SubComponent>();
// test it...
}
}
[Test]
public void SubComponentWorksGreatWithMocks()
{
var repoMock = new Mock<IRepository>();
using (var container = TestUtilities.CreateContainer(c =>
c.Register(Component.For<IRepository>().Instance(repoMock.Object))))
{
var subComponent = container.Resolve<SubComponent>();
// test it with all IRepository instances mocked...
}
}
One last note. Creating a full container for every test can get expensive. Another option is to create the full container but only using nested containers for the actual tests.
You don't "have to" new-up a form, as you've said.
I use WinForms and never call "new FormName()". It's always a dependency itself. Otherwise I'd have to stuff the constructor full of service locator calls.
I might use a ServiceLocator (as in another answer) BUT only at the very top level.
For example I have a Command pattern implemented to intercept toolbar buttons.
Looks something like this:
public void Handle(string commandName)
{
var command = IoC.Resolve<ICommand>(RegisteredCommands[commandName]);
command.Execute();
}
Then, in a simplified case, this is the kind of code written everywhere else:
public class ShowOptionsCommand : Command, ICommand
{
private readonly IOptionsView _optionsView;
public ShowOptionsCommand(IOptionsView optionsView)
{
_optionsView = optionsView;
}
public void Execute()
{
_optionsView.Show();
}
}
Yes, I use a "service locator" but you will hardly ever see it.
That's important to me, because having service locator calls all throughout the code (eg in every class) defeats some of the point of using dependency inversion of control & needs extra work to be testable etc