Why does my Nancy module generate an "Unable to resolve type" error at startup? - nancy

I added this nancy module to my previously working nancy application. It compiles, but at application startup I get an error : "Unable to resolve type: HubJH.Web.SignAndStore.SignAndStoreModule"
public class SignAndStoreModule : NancyModule
{
private IConnectionFactory connFac;
SignAndStoreModule(IConnectionFactory connFac)
{
this.connFac = connFac;
Post["/"] = p =>
{
return 200;
};
}
}
What am I doing wrong?

Ok silly me. The constructor needs to be public. So this works...
public class SignAndStoreModule : NancyModule
{
private IConnectionFactory connFac;
public SignAndStoreModule(IConnectionFactory connFac)
{
this.connFac = connFac;
Post["/"] = p =>
{
return 200;
};
}
}

Related

ABPFramwork - Remove api from layer application in swagger

I have created a project using abpframwork. When running swagger, swagger receives the function in the application layer is a api. I don't want that. Can you guys tell me how to remove it in swagger
Code in Application Layer
public class UserService : AdminSSOAppService, ITransientDependency, IValidationEnabled, IUserService
{
IUserRepository _userRepository;
private readonly ILogger<UserService> _log;
public UserService(IUserRepository userRepository,
ILogger<UserService> log
)
{
_userRepository = userRepository;
_log = log;
}
public async Task<List<UserDto>> GetList()
{
var list = await _userRepository.GetListAsync();
return ObjectMapper.Map<List<User>, List<UserDto>>(list);
}
public async Task<UserDto> GetUserById(int Id)
{
var user = await _userRepository.GetAsync(c=>c.Id == Id);
return ObjectMapper.Map<User, UserDto>(user);
}
}
Code in HttpApi Layer
[Area(AdminSSORemoteServiceConsts.ModuleName)]
[RemoteService(Name = AdminSSORemoteServiceConsts.RemoteServiceName)]
[Route("api/user/user-profile")]
public class UserController : ControllerBase, IUserService
{
private readonly IUserService _userAppService;
public UserController(IUserService userAppService)
{
_userAppService = userAppService;
}
[HttpGet]
[Route("get-list-httpapi")]
public Task<List<UserDto>> GetList()
{
return _userAppService.GetList();
}
[HttpGet]
[Route("get-by-id-httpapi")]
public Task<UserDto> GetUserById(int Id)
{
return _userAppService.GetUserById(Id);
}
}
I can suggest a workaround as to enable only the APIs you need to appear on swagger (though the ones that don't appear anymore will still be available for consumption).
I would suggest you add a configuration part in your *.Http.Api project module inside your ConfigureSwaggerServices, like so:
context.Services.AddSwaggerGen(options =>
{
options.DocInclusionPredicate(
(_, apiDesc) =>
apiDesc
.CustomAttributes()
.OfType<IncludeInSwaggerDocAttribute>()
.Any());
});
And for the attribute, it would be very simple, like so:
[AttributeUsage(AttributeTargets.Class)]
public class IncludeInSwaggerDocAttribute : Attribute
{
}
This will let you achieve what you want, however I still recommend reading the doc carefully to be able to implement DDD.

Problem loading view with MEF and ExportAttribute

I have a WPF app and I'm trying to use MEF to load viewmodels and view.
I can't successfully load Views.
The code:
public interface IContent
{
void OnNavigatedFrom( );
void OnNavigatedTo( );
}
public interface IContentMetadata
{
string ViewUri { get; }
}
[MetadataAttribute]
public class ExtensionMetadataAttribute : ExportAttribute
{
public string ViewUri { get; private set; }
public ExtensionMetadataAttribute(string uri) : base(typeof(IContentMetadata))
{
this.ViewUri = uri;
}
}
class ViewContentLoader
{
[ImportMany]
public IEnumerable<ExportFactory<IContent, IContentMetadata>> ViewExports
{
get;
set;
}
public object GetView(string uri)
{
// Get the factory for the View.
var viewMapping = ViewExports.FirstOrDefault(o =>
o.Metadata.ViewUri == uri);
if (viewMapping == null)
throw new InvalidOperationException(
String.Format("Unable to navigate to: {0}. " +
"Could not locate the View.",
uri));
var viewFactory = viewMapping.CreateExport();
var view = viewFactory.Value;
return viewFactory;
}
}
I supposed to use this code like this:
1)Decorate a User control
[Export(typeof(IContent))]
[ExtensionMetadata("CustomPause")]
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)]
public partial class CustomPause : Page , IContent, IPartImportsSatisfiedNotification
{
public CustomPause()
{
InitializeComponent();
}
}
2) Compose the parts:
var cv = new CompositionContainer(aggregateCatalog);
var mef = new ViewContentLoader();
cv.ComposeParts(mef);
3) Load the view at runtime given a URI, for example:
private void CustomPause_Click(object sender, RoutedEventArgs e)
{
var vc = GlobalContainer.Instance.GetMefContainer() as ViewContentLoader;
MainWindow.MainFrame.Content = vc.GetView ("CustomPause");
}
Problem is this line in the GetView method fails:
var viewMapping = ViewExports.FirstOrDefault(o =>
o.Metadata.ViewUri == uri);
The query fails and so viewMapping is null but composition seems ok and I can see that ViewExports contains an object of type:
{System.ComponentModel.Composition.ExportFactory<EyesGuard.MEF.IContent, EyesGuard.MEF.IContentMetadata>[0]
I don't know where I'm wrong. Do you have a clue?
Gianpaolo
I had forgot this
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
in the MetadataAttribute

Handling failed claim in Nancy

I am using the RequiresClaims mechanism in Nancy like this:
public class HomeModule : NancyModule
{
public HomeModule()
{
Get["/"] = ctx => "Go here";
Get["/admin"] = ctx =>
{
this.RequiresClaims(new[] { "boss" }); // this
return "Hello!";
};
Get["/login"] = ctx => "<form action=\"/login\" method=\"post\">" +
"<button type=\"submit\">login</button>" +
"</form>";
Post["/login"] = ctx =>
{
return this.Login(Guid.Parse("332651DD-A046-4489-B31F-B6FA1FB290F0"));
};
}
}
The problem is if the user is not allowed to enter /admin because the user doesn't have claim boss, Nancy just responds with http status 403 and blank body.
This is exactly what I need for the web service part of my application, but there are also parts of my application where nancy should construct page for user. How can I show something more informative to the user?
This is the user mapper that I use:
public class MyUserMapper : IUserMapper
{
public class MyUserIdentity : Nancy.Security.IUserIdentity
{
public IEnumerable<string> Claims { get; set; }
public string UserName { get; set; }
}
public Nancy.Security.IUserIdentity GetUserFromIdentifier(Guid identifier, Nancy.NancyContext context)
{
return new MyUserIdentity { UserName = "joe", Claims = new[] { "peon" } };
}
}
And this is the bootstrapper that I use:
public class MyNancyBootstrapper : DefaultNancyBootstrapper
{
protected override void RequestStartup(
Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines, NancyContext context)
{
base.RequestStartup(container, pipelines, context);
var formAuthConfig = new Nancy.Authentication.Forms.FormsAuthenticationConfiguration
{
RedirectUrl = "~/login",
UserMapper = container.Resolve<Nancy.Authentication.Forms.IUserMapper>()
};
Nancy.Authentication.Forms.FormsAuthentication.Enable(pipelines, formAuthConfig);
}
}
You need to handle the 403 status code as part of the pipeline and then return an html response to the user. Take a look at http://paulstovell.com/blog/consistent-error-handling-with-nancy

Provide custom rootpath to Nancy when using OWIN

I have a sample application that shows how to host Nancy on node.js.
To do that I need to change the rootpath. I ended up with something like that:
public class Startup
{
public static void Configuration(IAppBuilder app)
{
string rootpath = app.Properties["node.rootpath"] as string;
app.UseNancy(options => options.Bootstrapper = new NodeBootstrapper(rootpath));
}
}
public class NodeRootPathProvider : IRootPathProvider
{
private string rootpath;
public NodeRootPathProvider(string rootpath)
{
this.rootpath = rootpath;
}
public string GetRootPath()
{
return this.rootpath;
}
}
public class NodeBootstrapper : DefaultNancyBootstrapper
{
private string rootpath;
public NodeBootstrapper(string rootpath)
: base()
{
this.rootpath = rootpath;
}
protected override IRootPathProvider RootPathProvider
{
get { return new NodeRootPathProvider(this.rootpath); }
}
}
Is there a way to simplfy this?

MEF only loading Exports from local assembly

Im trying to make an app that can dynamically load classes that implements an interface "IPlugin", i have:
var catalog = new AssemblyCatalog(typeof(Shell).Assembly);
var externalCatalog = new DirectoryCatalog(#".\Modules");
var container = new CompositionContainer(catalog);
var a = new AggregateCatalog(externalCatalog, catalog);
But when im trying to get the exports:
CompositionContainer __container = new CompositionContainer(a);
//get all the exports and load them into the appropriate list tagged with the importmany
__container.Compose(batch);
var yyyy = __container.GetExports<IModule>();
It doesnt find my "IPlugin" in the external assembly "Rejseplan".
Implementation of "Rejseplan" plugin:(the one that does not get loaded)
namespace Rejseplan
{
[ModuleExport(typeof(IPlugin), InitializationMode = InitializationMode.WhenAvailable)]
class RejseplanModule : IModule, IPlugin
{
private readonly IRegionViewRegistry regionViewRegistry;
[ImportingConstructor]
public RejseplanModule(IRegionViewRegistry registry)
{
this.regionViewRegistry = registry;
}
public void Initialize()
{
regionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(Views.DepartureBoard));
}
string IPlugin.Name
{
get { throw new NotImplementedException(); }
}
string IPlugin.Version
{
get { throw new NotImplementedException(); }
}
string IPlugin.TabHeader
{
get { throw new NotImplementedException(); }
}
}
}
implmentation of "Test" plugin (the one that GETS loaded):
namespace HomeSystem
{
[Export(typeof(IPlugin))]
[ModuleExport(typeof(IModule), InitializationMode = InitializationMode.WhenAvailable)]
public class Test : IModule, IPlugin
{
public void Initialize()
{
}
public string Name
{
get { return "Test"; }
}
public string Version
{
get { return "Tis"; }
}
public string TabHeader
{
get { return "Tabt"; }
}
}
}
Hope you guys can helpCheers! :)
to be honest i dont really know what you wanna achieve :)
but if you want to see your RejseplanModule within your call:
__container.GetExports<IModule>();
you have to add the right Export attribute.
RejseplanModule is not MEF marked with Export of type IModule. can you check your code if its a typo or not? at least it should be the following (see the typeof(IModule))
EDIT:
external dll
[Export(typeof(IModule))]//<-- remove this if its handled by your custom ModulExport Attribute
[ModuleExport(typeof(IModule), InitializationMode = InitializationMode.WhenAvailable)]
class RejseplanModule : IModule, IPlugin
{...}
your main app(code from fhnaseer above)
var directoryPath = "path to dll folder";
var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var directoryCatalog = new DirectoryCatalog(directoryPath, "*.dll");
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(asmCatalog);
aggregateCatalog.Catalogs.Add(directoryCatalog);
var container = new CompositionContainer(aggregateCatalog);
var allIModulPlugins = container.GetExports<IModule>();
try to do this.
var directoryPath = "path to dll folder";
var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var directoryCatalog = new DirectoryCatalog(directoryPath, "*.dll");
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(asmCatalog);
aggregateCatalog.Catalogs.Add(directoryCatalog);
var container = new CompositionContainer(aggregateCatalog);
container.ComposeParts(this);

Resources