Navigation Problem in Xamarin android.When i clicked for navigation then i receive following Exception System.InvalidOperationException: No CurrentActivity found.
this is the app.cs class code
using GalaSoft.MvvmLight.Ioc;
using GalaSoft.MvvmLight.Threading;
using GalaSoft.MvvmLight.Views;
using SGDD.ViewModel;
using SGDD_Portal;
namespace SGDD
{
public static class App
{
private static ViewModelLocator _locator;
public static ViewModelLocator Locator
{
get
{
if (_locator == null)
{
// Initialize the MVVM Light DispatcherHelper.
// This needs to be called on the UI thread.
DispatcherHelper.Initialize();
// Configure and register the MVVM Light NavigationService
var nav = new NavigationService();
SimpleIoc.Default.Register<INavigationService>(() => nav);
nav.Configure(ViewModelLocator.SecondPageKey, typeof(SecondActivity));
nav.Configure(ViewModelLocator.DetailPageKey, typeof(DetailActivity));
// Register the MVVM Light DialogService
SimpleIoc.Default.Register<IDialogService, DialogService>();
_locator = new ViewModelLocator();
}
return _locator;
}
}
}
}
This is the ViewModelLocatar Code
using System.Diagnostics.CodeAnalysis;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using GalaSoft.MvvmLight.Views;
using Microsoft.Practices.ServiceLocation;
using SGDD_Portal;
using SGDD_Portal.Design;
using SGDD_Portal.Model;
using SGDD_Portal.ViewModel;
namespace SGDD.ViewModel
{
/// <summary>
/// This class contains static references to the most relevant view models in the
/// application and provides an entry point for the bindings.
/// <para>
/// See http://www.mvvmlight.net
/// </para>
/// </summary>
public class ViewModelLocator
{
/// <summary>
/// The key used by the NavigationService to go to the second page.
/// </summary>
public const string SecondPageKey = "SecondPage";
public const string DetailPageKey = "DetailPage";
/// <summary>
/// Gets the Main property.
/// </summary>
[SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public DetailViewModel DetailViewModel
{
get
{
return ServiceLocator.Current.GetInstance<DetailViewModel>();
}
}
/// <summary>
/// This property can be used to force the application to run with design time data.
/// </summary>
public static bool UseDesignTimeData
{
get
{
return false;
}
}
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (!ViewModelBase.IsInDesignModeStatic
&& !UseDesignTimeData)
{
// Use this service in production.
SimpleIoc.Default.Register<IDataService, DataService>();
}
else
{
// Use this service in Blend or when forcing the use of design time data.
SimpleIoc.Default.Register<IDataService, DesignDataService>();
}
SimpleIoc.Default.Register<MainViewModel>();
SimpleIoc.Default.Register<DetailViewModel>();
}
/// <summary>
/// Cleans up all the resources.
/// </summary>
public static void Cleanup()
{
}
}
}
This is the Declaration of ViewModel In Activity
private DetailViewModel DetailViewModel
{
get
{
return App.Locator.DetailViewModel;
}
}
This is The binding with click.
fabMain.SetCommand(
"Click",
DetailViewModel.CompanyCommand);
This is the DeatilViewModel Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Views;
using SGDD.ViewModel;
namespace SGDD_Portal.ViewModel
{
public class DetailViewModel : ViewModelBase
{
private INavigationService _navigationService;
public DetailViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
}
private RelayCommand _companyCommand;
public RelayCommand CompanyCommand
{
get
{
return _companyCommand
?? (_companyCommand = new RelayCommand(
async () =>
{
_navigationService.NavigateTo(ViewModelLocator.DetailPageKey);
}));
}
}
}
}
Related
I am are trying to get an instance of a Hub Class to call front-end methods from the backend from a class outside of the Hub class.
I am using IHostLifeTime that has a register function that will be running in the background while the server is running in a while loop.
There will be events in the while loop that will trigger signalR to send a message to the client.
Question: How am I supposed to get access to the hub and send a message to the client inside of my manager class in the ApplicationReady() function?
TestHub.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
namespace SignalREventHandle
{
public class TestHub : Hub
{
public async Task SendMessage(string user, string message)
{
Console.WriteLine($"user: {user} message:{message}");
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using System.Threading;
namespace SignalREventHandle
{
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.AddRazorPages();
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request //pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime, IHubContext<TestHub> hubContext)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
lifetime.ApplicationStarted.Register(OnAppStarted);
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<TestHub>("/testHub");
});
}
public async void OnAppStarted()
{
//Get Singleton Instance of Manager and then start the application
var manager = Manager.Instance;
manager.ApplicationReady();
}
}
}
Manager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace SignalREventHandle
{
public class Manager
{
private bool _isServerRunning;
/// <summary>
/// Instance of class to implement Singleton
/// </summary>
private static readonly Manager _instance = new();
/// <summary>
/// Getter for Class instance
/// </summary>
public static Manager Instance
{
get => _instance;
}
public async void ApplicationReady()
{
var task = Task.Run(() =>
{
_isServerRunning = true;
while (_isServerRunning)
{
// Want to Send Message to Client with SignalR here
Thread.Sleep(10000);
}
});
}
}
}
In ASP.NET 4.x SignalR use GlobalHost to provide access to the IHubContext:
public static async Task SendMessage(string user, string message)
{
Console.WriteLine($"user: {user} message: {message}");
// Get an instance of IHubContext from GlobalHost
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
await hubContext.Clients.All.SendAsync("ReceiveMessage", user, message);
}
In ASP.NET Core SignalR, you can access an instance of IHubContext from the web host.
Program.cs
public class Program
{
public static IHost WebHost;
public static void Main(string[] args)
{
WebHost = CreateHostBuilder(args).Build();
WebHost.Run();
}
...
}
Then:
public static async Task SendMessage(string user, string message)
{
Console.WriteLine($"user: {user} message: {message}");
// Get an instance of IHubContext from IHost
var hubContext = Program.WebHost.Services.GetService(typeof(IHubContext<ChatHub>)) as IHubContext<ChatHub>;
await hubContext.Clients.All.SendAsync("ReceiveMessage", user, message);
}
Documentation:
https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-5.0
signalr how i can i post a message from server to caller
I have two controllers both are derivated from a base controller. The code inside them is exactly the same. The only difference is in constructors. Below is my code:
[RoutePrefix("api/v2")]
public class CategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public CategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Categories
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("categoryRef")]
public HttpResponseMessage Categories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("categoryRef",null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
}
The second one is
[RoutePrefix("api/v2")]
public class ProblemCategoryController : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
/// <summary>
/// Constructor for initialization
/// </summary>
public ProblemCategoryController()
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
}
/// <summary>
/// Retrieve all Natures of problem
/// </summary>
/// <returns>Categories(Id, Label)</returns>
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest("problemCategoryRef", null);
response = Request.CreateResponse(HttpStatusCode.OK, categories);
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
Now as you can see the internal code is exactly the same which I want to avoid creating a Helper class. How can I make this common class for it so as to remove code duplicacy? It's possible without rewrite all the context code to get User and Id app?
I tried this
public class NatureOfProblemHelper : BaseController
{
private IGetTroubleTicketService getTroubleTicketService;
private ICategoryService categoryService;
private string resourceName;
/// <summary>
/// Initializes a new instance of the <see cref="NatureOfProblemHelper"/> class.
/// Constructor for initialization.
/// <param name="resource">Resource requested by user.</param>
/// </summary>
public NatureOfProblemHelper(string resource)
{
getTroubleTicketService = MethodFactory.Create<IGetTroubleTicketService>();
getTroubleTicketService.SetProvider(new ServiceProvider(Global.Container));
categoryService = MethodFactory.Create<ICategoryService>();
categoryService.SetProvider(new ServiceProvider(Global.Container));
resourceName = resource;
}
/// <summary>
/// Retrieve all Natures of problem.
/// </summary>
/// <returns>Categories(Id, Label).</returns>
public HttpResponseMessage GetNaturesOfProblem()
{
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
var userLanaguage = Convert.ToInt32(user.Language, CultureInfo.InvariantCulture);
var categories = categoryService.CategoriesData(userLanaguage);
LoggingRequest(resourceName, null);
return Request.CreateResponse(HttpStatusCode.OK, categories);
}
And then into each controller
[HttpGet]
[Route("problemCategoryRef")]
public HttpResponseMessage ProblemCategories()
{
try
{
response = natureOfProblem.NaturesOfProblem();
}
catch (Exception exception)
{
//CheckError
CheckError(exception);
}
return response;
}
This build, but I can't get the context that comes from this variable
// Validate User Id and Application Id
var user = ValidateUserAndApplication(getTroubleTicketService);
Why if I put the same lines of code directly in my controller works but if I put in my Helper it doesn't work??
I am facing a problem when try to write a web job scheduler. I am using Ninject scope binding using EF Repository pattern. But Only InSingletonScope() work as expected. How to configure it in RequestScope Or Call Scope ?
//Register Context
Kernel.Bind<MyDbContext>().ToSelf().InSingletonScope();
Kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>().InSingletonScope();
Problem Solved From One of My Previous Post
I am posting Step By Step Solution
(1.) NinjectJobActivator
public class NinjectJobActivator : IJobActivator
{
#region Variable Declaration
private readonly IResolutionRoot _resolutionRoot;
#endregion
#region CONSTRUCTOR
/// <summary>
///
/// </summary>
/// <param name="kernel"></param>
// public NinjectJobActivator(IKernel kernel)
public NinjectJobActivator(IResolutionRoot resolutionRoot)
{
_resolutionRoot = resolutionRoot;
}
#endregion
#region CreateInstance
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T CreateInstance<T>()
{
return _resolutionRoot.Get<T>(new CallScopedParameter());
}
#endregion
}
(2) NinjectBindings
using Ninject.Extensions.Conventions;
using Ninject.Extensions.NamedScope;
public class NinjectBindings : NinjectModule
{
public override void Load()
{
//Register Context
Kernel.Bind<MyDbContext>().ToSelf()
.When(x => x.Parameters.OfType<CallScopedParameter>().Any())
.InCallScope(); // For Scheduler
Kernel.Bind<IUnitOfWork<MyDbContext>>().To<UnitOfWork<MyDbContext>>();
//Register Repository
Kernel.Bind(x => x
.FromAssemblyContaining<MyDbContext>()
.SelectAllClasses()
.InheritedFrom(typeof(IRepository<>))
.BindDefaultInterface());
}
}
(3) Program.cs
static void Main()
{
using (IKernel kernel = new StandardKernel(new NinjectBindings()))
{
var config = new JobHostConfiguration()
{
JobActivator = new NinjectJobActivator(kernel)
};
if (config.IsDevelopment)
{
config.UseDevelopmentSettings();
}
// Timer Trigger
config.UseTimers();
var host = new JobHost(config);
//// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
}
(4) CallScopedParameter
public sealed class CallScopedParameter : IParameter
{
/// <summary>
///
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is CallScopedParameter;
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="target"></param>
/// <returns></returns>
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
/// <summary>
///
/// </summary>
public string Name
{
get { return typeof(CallScopedParameter).Name; }
}
/// <summary>
/// this is very important
/// </summary>
public bool ShouldInherit
{
get { return true; }
}
}
(5) Azure Web Job Function
public void DoSomething([TimerTrigger("*/30 * * * * *")] TimerInfo timer, TextWriter log)
{
try
{
var tempdetails = _sampleRepository.SearchFor(x=> DateTime.UtcNow > x.DateTo);
foreach (var detail in tempdetails)
{
if (detail.ID == 2)
{
detail.ID = 5;
}
_sampleRepository.Update(detail);
}
_unitOfWork.Commit();
}
catch (Exception ex)
{
log.WriteLine(ex.Message);
}
}
Please help me out. I am stuck with the service registration. I tried every possible aspect from google but could not conclude. What I am trying to do is create a new table EducationDegree, a master table. The Consumer will then be assigned Education degree.
My issue is with the EducationDegreeService registration. Please see constructor created in Nop.web>Controllers> CustomController.cs and registration done in Nop.web>Framework> dependencyregister.cs. Additional code commented as
//Added By Shyam
It’s been more than a week and I have not been able to crack it. So please help me out.
Below here is the error message
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Nop.Web.Controllers.CustomerController' can be invoked with the available services and parameters:
Cannot resolve parameter 'Nop.Services.EducationDegrees.EducationDegreeService educationDegreeService' of constructor 'Void .ctor(Nop.Services.Authentication.IAuthenticationService, Nop.Services.Helpers.IDateTimeHelper, Nop.Services.Helpers.DateTimeSettings, Nop.Core.Domain.Tax.TaxSettings, Nop.Services.Localization.ILocalizationService, Nop.Core.IWorkContext, Nop.Core.IStoreContext, Nop.Services.Stores.IStoreMappingService, Nop.Services.Customers.ICustomerService, Nop.Services.Customers.ICustomerAttributeParser, Nop.Services.Customers.ICustomerAttributeService, Nop.Services.Common.IGenericAttributeService, Nop.Services.Customers.ICustomerRegistrationService, Nop.Services.Tax.ITaxService, Nop.Core.Domain.Customers.RewardPointsSettings, Nop.Core.Domain.Customers.CustomerSettings, Nop.Core.Domain.Common.AddressSettings, Nop.Core.Domain.Forums.ForumSettings, Nop.Core.Domain.Orders.OrderSettings, Nop.Services.Common.IAddressService, Nop.Services.Directory.ICountryService, Nop.Services.Directory.IStateProvinceService, Nop.Services.Orders.IOrderTotalCalculationService, Nop.Services.Orders.IOrderProcessingService, Nop.Services.Orders.IOrderService, Nop.Services.Directory.ICurrencyService, Nop.Services.Catalog.IPriceFormatter, Nop.Services.Media.IPictureService, Nop.Services.Messages.INewsLetterSubscriptionService, Nop.Services.Forums.IForumService, Nop.Services.Orders.IShoppingCartService, Nop.Services.Authentication.External.IOpenAuthenticationService, Nop.Services.Catalog.IBackInStockSubscriptionService, Nop.Services.Media.IDownloadService, Nop.Core.IWebHelper, Nop.Services.Logging.ICustomerActivityService, Nop.Core.Domain.Media.MediaSettings, Nop.Services.Messages.IWorkflowMessageService, Nop.Core.Domain.Localization.LocalizationSettings, Nop.Web.Framework.UI.Captcha.CaptchaSettings, Nop.Core.Domain.Customers.ExternalAuthenticationSettings, Nop.Services.EducationDegrees.EducationDegreeService)'
And here is the code I have added
Nop.Core>Domain >Educationdegrees
using Nop.Core.Domain.Localization;
namespace Nop.Core.Domain.EducationDegrees
{
public partial class EducationDegree: BaseEntity, ILocalizedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the page size
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// Gets or sets a value indicating whether customers can select the page size
/// </summary>
public bool AllowCustomersToSelectPageSize { get; set; }
/// <summary>
/// Gets or sets the available customer selectable page size options
/// </summary>
public string PageSizeOptions { get; set; }
}
}
Nop.Data>Mapping>Education Degree – EducationDegreeMap.cs
using System.Data.Entity.ModelConfiguration;
using Nop.Core.Domain.EducationDegrees;
namespace Nop.Data.Mapping.EducationDegrees
{
public partial class EducationDegreeMap : EntityTypeConfiguration<EducationDegree>
{
public EducationDegreeMap()
{
this.ToTable("EducationDegree");
this.HasKey(v => v.Id);
this.Property(v => v.Name).IsRequired().HasMaxLength(1000);
}
}
}
Nop.Services>EducationDegree>EducationDegreeService.cs
using System;
using System.Linq;
using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Domain.EducationDegrees;
using Nop.Services.Events;
namespace Nop.Services.EducationDegrees
{
public partial class EducationDegreeService : IEducationDegreeService
{
#region Fields
private readonly IRepository<EducationDegree> _educationdegreeRepository;
private readonly IEventPublisher _eventPublisher;
#endregion
#region Ctor
/// <summary>
/// Ctor
/// </summary>
/// <param name="educatioRepository">Vendor repository</param>
/// <param name="eventPublisher">Event published</param>
public EducationDegreeService(IRepository<EducationDegree> educationdegreeRepository,
IEventPublisher eventPublisher)
{
this._educationdegreeRepository = educationdegreeRepository;
this._eventPublisher = eventPublisher;
}
#endregion
#region Methods
/// <summary>
/// Gets all vendors
/// </summary>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>Vendors</returns>
public virtual IPagedList<EducationDegree> GetAllEducationDegrees(int pageIndex = 0, int pageSize = int.MaxValue, bool showHidden = false)
{
var query = _educationdegreeRepository.Table;
query = query.OrderBy(v => v.Name);
var educationdegrees = new PagedList<EducationDegree>(query, pageIndex, pageSize);
return educationdegrees;
}
#endregion
}
}
Nop.Services>EducationDegree>IEducationDegreeService.cs
using Nop.Core;
using Nop.Core.Domain.EducationDegrees;
namespace Nop.Services.EducationDegrees
{
public partial interface IEducationDegreeService
{
/// <summary>
/// Gets all vendors
/// </summary>
/// <param name="showHidden">A value indicating whether to show hidden records</param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>Vendors</returns>
IPagedList<EducationDegree> GetAllEducationDegrees(int pageIndex = 0, int pageSize = int.MaxValue, bool showHidden = false);
}
}
Nop.Web>Infrastructure>DependencyRegister.cs
using Autofac;
using Autofac.Core;
using Nop.Core.Caching;
using Nop.Core.Infrastructure;
using Nop.Core.Infrastructure.DependencyManagement;
using Nop.Web.Controllers;
using Nop.Web.Infrastructure.Installation;
using Nop.Services.EducationDegrees;
namespace Nop.Web.Infrastructure
{
public class DependencyRegistrar : IDependencyRegistrar
{
public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder)
{
//we cache presentation models between requests
builder.RegisterType<BlogController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<CatalogController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<CountryController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<CommonController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<NewsController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<PollController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<ProductController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<ShoppingCartController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<TopicController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
builder.RegisterType<WidgetController>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"));
//installation localization service
builder.RegisterType<InstallationLocalizationService>().As<IInstallationLocalizationService>().InstancePerLifetimeScope();
//Added by Shyam
builder.RegisterType<EducationDegreeService>().As<IEducationDegreeService>().InstancePerLifetimeScope();
}
public int Order
{
get { return 2; }
}
}
}
Nop.Web>Models>EducationDegrees
using System.Collections.Generic;
using System.Web.Mvc;
using FluentValidation.Attributes;
using Nop.Web.Framework;
using Nop.Web.Framework.Localization;
using Nop.Web.Framework.Mvc;
namespace Nop.Web.Models.EducationDegrees
{
public partial class EducationDegreeModel : BaseNopEntityModel
{
public EducationDegreeModel()
{
}
[NopResourceDisplayName("Education Degree")]
[AllowHtml]
public string Name { get; set; }
}
}
Nop.Web>Models>Customer>registerModel.cs
public RegisterModel()
{
this.AvailableTimeZones = new List<SelectListItem>();
this.AvailableCountries = new List<SelectListItem>();
this.AvailableStates = new List<SelectListItem>();
this.CustomerAttributes = new List<CustomerAttributeModel>();
//Added By Shyam
this.AvailableEducationDegrees = new List<SelectListItem>();
}
//Added By Shyam
public int? EducationDegreeId { get; set; }
public IList<SelectListItem> AvailableEducationDegrees { get; set; }
Nop.Web>Models>Customer>customerinfoModel.cs
//Added by Shyam
[NopResourceDisplayName("What is the highest educational degree that you have obtained (select one)?")]
public int? EducationDegreeId { get; set; }
public IList<SelectListItem> AvailableEducationDegree { get; set; }
Nop.web>Controllers> EducationDegreeController.cs
using System.Linq;
using System.Web.Mvc;
using Nop.Core.Domain.Vendors;
using Nop.Services.EducationDegrees;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Kendoui;
namespace Nop.Web.Controllers
{
public partial class EducationDegreeController : BasePublicController
{
#region Fields
private readonly IEducationDegreeService _educationdegreeService;
#endregion
#region Constructors
public EducationDegreeController(IEducationDegreeService educationdegreeService)
{
this._educationdegreeService = educationdegreeService;
}
#endregion
#region Methods
//list
public ActionResult Index()
{
return RedirectToAction("List");
}
#endregion
}
}
Nop.web>Framework> dependencyregister.cs
//Added by Shyam
using Nop.Services.EducationDegrees;
namespace Nop.Web.Framework
{
public class DependencyRegistrar : IDependencyRegistrar
{
public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder)
{
. . . . . . .
. . . . . . . .
//Added by Shyam
builder.RegisterType<EducationDegreeService>().As<IEducationDegreeService>().InstancePerLifetimeScope();
}
}
}
Nop.web>Controllers> CustomController.cs
using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Nop.Web.Models.Customer;
//Added by shyam
using Nop.Services.EducationDegrees;
namespace Nop.Web.Controllers
{
public partial class CustomerController : BasePublicController
{
#region Fields
private readonly ExternalAuthenticationSettings _externalAuthenticationSettings;
//Added by Shyam
private readonly IEducationDegreeService _educationdegreeService;
#endregion
#region Ctor
public CustomerController(IAuthenticationService authenticationService,
IDateTimeHelper dateTimeHelper,
DateTimeSettings dateTimeSettings,
TaxSettings taxSettings,
ILocalizationService localizationService,
IWorkContext workContext,
IStoreContext storeContext,
IStoreMappingService storeMappingService,
ICustomerService customerService,
ICustomerAttributeParser customerAttributeParser,
ICustomerAttributeService customerAttributeService,
IGenericAttributeService genericAttributeService,
ICustomerRegistrationService customerRegistrationService,
ITaxService taxService, RewardPointsSettings rewardPointsSettings,
CustomerSettings customerSettings,AddressSettings addressSettings, ForumSettings forumSettings,
OrderSettings orderSettings, IAddressService addressService,
ICountryService countryService, IStateProvinceService stateProvinceService,
IOrderTotalCalculationService orderTotalCalculationService,
IOrderProcessingService orderProcessingService, IOrderService orderService,
ICurrencyService currencyService, IPriceFormatter priceFormatter,
IPictureService pictureService, INewsLetterSubscriptionService newsLetterSubscriptionService,
IForumService forumService, IShoppingCartService shoppingCartService,
IOpenAuthenticationService openAuthenticationService,
IBackInStockSubscriptionService backInStockSubscriptionService,
IDownloadService downloadService, IWebHelper webHelper,
ICustomerActivityService customerActivityService, MediaSettings mediaSettings,
IWorkflowMessageService workflowMessageService, LocalizationSettings localizationSettings,
CaptchaSettings captchaSettings, ExternalAuthenticationSettings externalAuthenticationSettings, EducationDegreeService educationDegreeService)
{
//Added by Shyam
this._educationdegreeService = educationDegreeService;
this._authenticationService = authenticationService;
this._dateTimeHelper = dateTimeHelper;
this._dateTimeSettings = dateTimeSettings;
this._taxSettings = taxSettings;
this._localizationService = localizationService;
this._workContext = workContext;
this._storeContext = storeContext;
this._storeMappingService = storeMappingService;
this._customerService = customerService;
this._customerAttributeParser = customerAttributeParser;
this._customerAttributeService = customerAttributeService;
this._genericAttributeService = genericAttributeService;
this._customerRegistrationService = customerRegistrationService;
this._taxService = taxService;
this._rewardPointsSettings = rewardPointsSettings;
this._customerSettings = customerSettings;
this._addressSettings = addressSettings;
this._forumSettings = forumSettings;
this._orderSettings = orderSettings;
this._addressService = addressService;
this._countryService = countryService;
this._stateProvinceService = stateProvinceService;
this._orderProcessingService = orderProcessingService;
this._orderTotalCalculationService = orderTotalCalculationService;
this._orderService = orderService;
this._currencyService = currencyService;
this._priceFormatter = priceFormatter;
this._pictureService = pictureService;
this._newsLetterSubscriptionService = newsLetterSubscriptionService;
this._forumService = forumService;
this._shoppingCartService = shoppingCartService;
this._openAuthenticationService = openAuthenticationService;
this._backInStockSubscriptionService = backInStockSubscriptionService;
this._downloadService = downloadService;
this._webHelper = webHelper;
this._customerActivityService = customerActivityService;
this._mediaSettings = mediaSettings;
this._workflowMessageService = workflowMessageService;
this._localizationSettings = localizationSettings;
this._captchaSettings = captchaSettings;
this._externalAuthenticationSettings = externalAuthenticationSettings;
}
}}
yes you are Right user3838557 :
Nop.Web.Controllers constructor declaration.
Instead of declaring
"EducationDegreeService educationDegreeService"
You should have used
IEducationDegreeService educationDegreeService"
Been struggling with this for quite a while now, so I'm starting to think I have created an anti-pattern. Nevertheless, here goes;
//Register self
container.Register(Component.For<IWindsorContainer>().Instance(container));
//Register all
container.Register(Component.For<IService1>().ImplementedBy<Service1>());
container.Register(Component.For<IService2>().ImplementedBy<Service2>());
//etc
IService1
{
//blabla
}
IService2 {IService1 Service1{get;}}
So IService1 and IService2 can be created without anything special.
Starting at IService3, an IProject is involved.
IProject{}
//Resolve a service that, amongst other things, relies on an IProject
IProjectGet
{
T Get<T>(IProject proj)
where T : class;
}
//Impl
ProjectGet : IProjectGet
{
IWindsorContainer _cont;
public ProjectGet(IWindsorContainer cont){_cont=cont}
public T Get<T>(IProject proj)
{
//Resolve using the main (and only) container and pass the IProject
return _cont.Resolve<T>(new {p = proj});
}
}
This does not work, only the main service is resolved with the
'p = proj' and any other dependencies the main service has, that also rely on the project,
cause an exception saying the project service was not found.
IService3
{
IService2 Service2{get;}
IProjectGet ProjectGet{get;}
IProjectLevelStuff SetActiveProject(IProject proj);
}
Service3 : IService3
{
IService2 Service2{get;private set;}
IProjectGet ProjectGet{get;private set;}
public Service3(IService2 s2, IProjectGet p)
{
ProjectGet = p;
Service2 = s2;
}
public IProjectLevelStuff SetActiveProject(IProject proj)
{
return ProjectGet.Get<IProjectLevelStuff>(proj);
}
}
ProjectLevelStuff : IProjectLevelStuff
{
IProject Project{get;private set;}
IService4 Service4 {get;private set;}
public ProjectLevelStuff(IProject p, IService4)//etc.
}
IService4
{
IService2 Service2{get;}
IService5 Service5{get;}
IService6 Service6{get;}
IProject Project{get;}
}
IService5{IProject Project{get;}}
IService6{IProject Project{get;}}
This fails because only ProjectLevelStuff gets the IProject passed to it, and since IService4 and it's dependencies also need it, an exception is thrown. Even if this did work, I don't like it, because each service with a dependency on IProject is forced to call that parameter 'p' which I want to avoid.
I just want to keep on using the services I already had but this time add the IProject instance that was passed to our generic Get method as a resolvable dependency. I have found no way to copy the container and creating a new one and then adding the main one as a child does not change anything (dependency still missing). How is this done?
Castle Windsor does have a TypeFactory built in but it essentially does the same thing as what I'm already doing and does not solve anything. The only 'solution' I found is creating a new container and registering the types all over again but this time resolve them via the main container (except for the IProject of course).. it's a maintenance nightmare in the works.
UPDATE: I added some unit tests to my answer below that hopefully clears up some things
please check if you could use the approach below using scopes:
[SetUp]
public void Setup()
{
int counter = 0;
_container = new WindsorContainer();
_container.AddFacility<TypedFactoryFacility>();
_container.Register(
Component.For<IService1>().ImplementedBy<Service1>().LifestyleScoped(),
Component.For<IService2>().ImplementedBy<Service2>().LifestyleScoped(),
Component.For<IService3>().ImplementedBy<Service3>().LifestyleScoped(),
Component.For<Class1>().LifestyleTransient(),
Component.For<Class2>().LifestyleTransient(),
Component.For<IProject>().ImplementedBy<Project>().LifestyleScoped().DynamicParameters((k, d) => d["name"] = "MyProjectName"+counter++)
);
}
[Test]
public void TestClass1()
{
using (_container.BeginScope())
{
Class1 object1 = _container.Resolve<Class1>();;
var object2 = _container.Resolve<Class1>();
Assert.AreNotSame(object1, object2);
Assert.AreSame(object1.Service1, object2.Service1);
}
}
[Test]
public void TestClass2()
{
Class2 object1;
using (_container.BeginScope())
{
object1 = _container.Resolve<Class2>();
var object2 = _container.Resolve<Class2>();
Assert.AreNotSame(object1, object2);
Assert.AreSame(object1.Project, object2.Project);
Assert.AreSame(object1.Service2.Project, object2.Service2.Project);
}
Class2 object3;
using (_container.BeginScope())
{
object3 = _container.Resolve<Class2>();
}
Assert.AreNotSame(object1.Project, object3.Project);
}
For some strange (but probably valid) reason Windsor child-containers can access their Parent containers but not the other way around. This means that in order to use services registered in the main container from the new container, we have to set the Parent of the main container rather than that of the new container.
This is painfully inconvenient because a container can only have one Parent.
internal class ProjServices : IProjServices
{
private readonly IKwProject _proj;
private readonly IWindsorContainer _mainCont;
public ProjServices(IKwProject proj, IWindsorContainer mainCont)
{
_mainCont = mainCont;
_proj = proj;
}
public T Resolve<T>()
{
T rett;
//Create new container
var projCont = new WindsorContainer();
//Register new service
projCont.Register(Component.For<IKwProject>().Instance(_proj));
//Set hierarchy
lock (_mainCont)
{
projCont.AddChildContainer(UiContainer); //ui needs project, set parent to projCont
UiContainer.AddChildContainer(_mainCont); //main needs ui, set parent to uiCont
//Resolve using main, which now has access to UI and Project services
try
{
rett = _mainCont.Resolve<T>();
}
finally
{
projCont.RemoveChildContainer(UiContainer);
UiContainer.RemoveChildContainer(_mainCont);
}
}
return rett;
}
private static readonly object UIContainerLock = new object();
private static volatile IWindsorContainer _uiContainer;
private static IWindsorContainer UiContainer
{
get
{
if(_uiContainer==null)
lock(UIContainerLock)
if (_uiContainer == null)
{
//Register the UI services
}
return _uiContainer;
}
}
}
And now if I wanted to use these new containers in even newer containers in the future I think I'd get stuck again due to the one-parent-only thing.... how do I properly do this, please?
UPDATE:
Unit Tests for VS 2010 and 2012:
ServiceTest.zip (798 KB)
https://mega.co.nz/#!z4JxUDoI!UEnt3TCoMFVg-vXKEAaJrhzjxfhcvirsW2hv1XBnZCc
Or to copy&paste:
using System;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ServiceTest
{
/// <summary>
/// A service that doesn't rely on anything else
/// </summary>
public interface IService1
{
}
class Service1 : IService1
{
}
/// <summary>
/// The Project
/// </summary>
public interface IProject
{
string Name { get; }
}
public class Project : IProject
{
public Project(string name)
{
Name = name;
}
public string Name { get; private set; }
}
/// <summary>
/// A Service that relies on a Project
/// </summary>
public interface IService2
{
IProject Project { get; }
string GetProjectName();
}
/// <summary>
/// The implementation shows it also relies on IService3
/// </summary>
public class Service2 : IService2
{
public Service2(IProject project, IService3 service3)
{
Project = project;
Service3 = service3;
}
public IProject Project { get; private set; }
public IService3 Service3 { get; private set; }
public string GetProjectName()
{
return Project.Name;
}
}
/// <summary>
/// IService3 is a Service that also relies on the Project
/// </summary>
public interface IService3
{
IProject Project { get; }
}
public class Service3 : IService3
{
public Service3(IProject project)
{
Project = project;
}
public IProject Project { get; private set; }
}
/// <summary>
/// Class1 uses the service without any dependencies so it will be easy to resolve
/// </summary>
public class Class1
{
public Class1(IService1 service1)
{
Service1 = service1;
}
public IService1 Service1 { get; private set; }
}
/// <summary>
/// Class2 also uses that service, but it also relies on a Project ánd IService2
/// which as you know also relies on the Project and IService3 which also relies on
/// the Project
/// </summary>
public class Class2
{
public Class2(IService1 service1, IProject project, IService2 service2)
{
Service1 = service1;
Project = project;
Service2 = service2;
}
public IProject Project { get; private set; }
public IService1 Service1 { get; private set; }
public IService2 Service2 { get; private set; }
}
/// <summary>
/// Set up the base services
/// </summary>
[TestClass]
public class UnitTestBase
{
protected WindsorContainer Cont;
[TestInitialize]
public void BaseSetup()
{
Cont = new WindsorContainer();
Cont.Register(Component.For<IService1>().ImplementedBy<Service1>().LifestyleTransient());
Cont.Register(Component.For<IService2>().ImplementedBy<Service2>().LifestyleTransient());
Cont.Register(Component.For<IService3>().ImplementedBy<Service3>().LifestyleTransient());
Cont.Register(Component.For<Class1>().LifestyleTransient());
Cont.Register(Component.For<Class2>().LifestyleTransient());
}
[TestMethod]
public void Class1_Resolves()
{
Cont.Resolve<Class1>();
}
}
/// <summary>
/// Set up the base unit tests
/// </summary>
[TestClass]
public class UnitTestClass2Base : UnitTestBase
{
protected void RunTest3Times(Func<string, IWindsorContainer> getContainer)
{
const string projNameBase = "MyProjectName";
Func<int, string> getProjectName = i => projNameBase + i;
for (var i = 0; i < 3; i++)
{
var pName = getProjectName(i);
GetClass2ForProject(getContainer(pName), pName);
}
}
protected void GetClass2ForProject(IWindsorContainer cont, string projName)
{
var c2 = cont.Resolve<Class2>();
Assert.IsTrue(c2.Project.Name == projName);
Assert.IsTrue(c2.Service2.Project.Name == projName);
Assert.IsTrue(c2.Service2.GetProjectName() == projName);
}
}
/// <summary>
/// This will fail on the second request because we cannot
/// overwrite the earlier registration. And iirc containers can't
/// be altered after the first resolve.
/// </summary>
[TestClass]
public class Attempt_1 : UnitTestClass2Base
{
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests()
{
RunTest3Times(s =>
{
Cont.Register(Component.For<IProject>().Instance(new Project(s)));
return Cont;
});
}
}
/// <summary>
/// It looks like we have to create a new container for every Project
/// So now the question remains; how do we get to keep using the base IService implementations
/// in the container that is scoped for the IProject?
/// </summary>
[TestClass]
public class Attempt_2 : UnitTestClass2Base
{
static IWindsorContainer CreateContainer(IProject p)
{
var ret = new WindsorContainer();
ret.Register(Component.For<IProject>().Instance(p));
return ret;
}
/// <summary>
/// This will fail because the services in the main
/// container can't access the IProject in the new container
/// </summary>
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests_1()
{
RunTest3Times(s =>
{
//Add the project container as a Child to the Main container
var projCont = CreateContainer(new Project(s));
Cont.AddChildContainer(projCont);
return Cont;
});
}
/// <summary>
/// Doing the previous approach the other way around works.
/// But now we can only resolve one thing at a time
/// </summary>
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests_2()
{
IWindsorContainer projCont = null;
//Add the Main container as a Child to the project container
// (in other words set the Parent of Main to Project)
// and then resolve using the main container.
//A container can only have one parent at a time so we can only
// resolve one scoped thing at a time.
RunTest3Times(s =>
{
if (projCont != null)
projCont.RemoveChildContainer(Cont);
projCont = CreateContainer(new Project(s));
projCont.AddChildContainer(Cont);
return Cont;
});
}
/// <summary>
/// The only way around that issue seems to be to register all project-dependent
/// services in the new container. Then re-register all original services
/// in the new container and pass the resolving on to the main container;
/// a maintenance nightmare and especially painful for named registrions.
/// </summary>
[TestMethod]
public void Class2_Resolves_Project_Scoped_Requests_3()
{
Func<IProject, IWindsorContainer> createContainer2 = p =>
{
var contNew = new WindsorContainer();
//Pass resolving of the non-dependent services on to the main container.
// this way it will respect it's lifestyle rules and not create new
// instances of services we wanted to use as a singleton etc.
contNew.Register(Component.For<IService1>().UsingFactoryMethod(() => Cont.Resolve<IService1>()).LifestyleTransient());
contNew.Register(Component.For<Class1>().UsingFactoryMethod(() => Cont.Resolve<Class1>()).LifestyleTransient());
//Register the dependent services directly in the new container so they can access the project
contNew.Register(Component.For<IService2>().ImplementedBy<Service2>().LifestyleTransient());
contNew.Register(Component.For<IService3>().ImplementedBy<Service3>().LifestyleTransient());
contNew.Register(Component.For<Class2>().LifestyleTransient());
contNew.Register(Component.For<IProject>().Instance(p));
return contNew;
};
RunTest3Times(s =>
{
var projCont = createContainer2(new Project(s));
return projCont;
});
}
}
}