Can someone help me with this? I'm trying to use Unity IoC for injection. Here's the code:
IUnityContainer container = new UnityContainer()
.RegisterType<IBaseModel, EmployeeModel>()
.RegisterType<IProxyObjectAdapter, EmployeeProxyObjectAdapter>()
.RegisterType<IAdventureWorksRepository<IProxyObjectAdapter>,AdventureWorksWCFRepository<IProxyObjectAdapter>>();
Unity is complaining at that last line. Here's the error message:
'AdventureWorksManagement.ServiceAgents.AdventureWorksWCFRepository'
cannot be used as type parameter 'TTo'
in the generic type or method
'Microsoft.Practices.Unity.UnityContainerExtensions.RegisterType(Microsoft.Practices.Unity.IUnityContainer,
params
Microsoft.Practices.Unity.InjectionMember[])'.
There is no implicit reference
conversion from
'AdventureWorksManagement.ServiceAgents.AdventureWorksWCFRepository'
to
'AdventureWorksManagement.ServiceAgents.IAdventureWorksRepository'. C:\My Development\My Testing
Ground\MyTesting
Ground\AdventureWorksManagement\ModelView\EmployeeViewModel.cs 94 33 AdventureWorksManagement
Here's the class definition:
/// <summary>
/// Repository for WCF agents
/// </summary>
public class AdventureWorksWCFRepository<T> : IAdventureWorksRepository<IBaseModel> where T: IProxyObjectAdapter
{
/// <summary>
/// WCF service end
/// </summary>
private readonly AdvWorksManagementService.EmployeeServiceContractClient servicePoint;
/// <summary>
/// Adapter used to translate WCF proxy objects to domain objects
/// </summary>
private T proxyobjectAdapter;
.....
Please advice.
dormantroot
The error is correct. You're mapping:
IAdventureWorksRepository<IProxyObjectAdapter> -> AdventureWorksWCFRepository<IProxyObjectAdapter>
However, in the code definition, AdventureWorkdsWCFRepository<T> implements IAdventureWorksRepository<IBaseModel>. Which is not the interface you're trying to map from. I suspect that IBaseModel was supposed to be "T" in the code.
Related
I am trying to move into .net core an existing .net application that is using CallContext.LogicalGet/SetData.
When a web request hits the application I save a CorrelationId in the CallContext and whenever I need to log something later down the track I can easily collect it from the CallContext, without the need to transfer it everywhere.
As CallContext is no longer supported in .net core since it is part of System.Messaging.Remoting what options are there?
One version I have seen is that the AsyncLocal could be used (How do the semantics of AsyncLocal differ from the logical call context?) but it looks as if I would have to transmit this variable all over which beats the purpose, it is not as convenient.
Had this problem when we switched a library from .Net Framework to .Net Standard and had to replace System.Runtime.Remoting.Messaging CallContext.LogicalGetData and CallContext.LogicalSetData.
I followed this guide to replace the methods:
http://www.cazzulino.com/callcontext-netstandard-netcore.html
/// <summary>
/// Provides a way to set contextual data that flows with the call and
/// async context of a test or invocation.
/// </summary>
public static class CallContext
{
static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();
/// <summary>
/// Stores a given object and associates it with the specified name.
/// </summary>
/// <param name="name">The name with which to associate the new item in the call context.</param>
/// <param name="data">The object to store in the call context.</param>
public static void SetData(string name, object data) =>
state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = data;
/// <summary>
/// Retrieves an object with the specified name from the <see cref="CallContext"/>.
/// </summary>
/// <param name="name">The name of the item in the call context.</param>
/// <returns>The object in the call context associated with the specified name, or <see langword="null"/> if not found.</returns>
public static object GetData(string name) =>
state.TryGetValue(name, out AsyncLocal<object> data) ? data.Value : null;
}
You can use a dictionary of AsyncLocal to simulate exactly the API and behavior of the original CallContext. See http://www.cazzulino.com/callcontext-netstandard-netcore.html for a complete implementation example.
I'm using Prism 6, UWP with Unity.
The ViewModels will be automatically injected into the datacontext of the page. However, when I navigate between the pages the viewmodels will always be recreated. Is this behaviour desired by Prism and Unity?
Imagine the following scenario, a user enter some data into a page therefore the proper properties of the viewmodel will be set. When the user is switching back to another page and revisits the page all entered data are lost, because a new viewmodel instance is created.
At the moment my workaround is to override OnNavigatedTo and OnNavigatingFrom to save all properties of the viewmodel with the SessionStateService manual. I'm not sure if this is the correct way?
You can reproduce this behaviour with the following example:
https://github.com/PrismLibrary/Prism-Samples-Windows/tree/master/SplitViewSample/SplitViewSample
I am not using Prism, I'm using modified version of Template 10.
I just had a quick look at the Prism source code. Looks like Template 10 borrowed a lot of ideas from Prism.
I'll try to answer your question from 2 perspectives:
1) AFAIK, in Prism there is a static class with which you can set how to create/resolve you view model when it is automatically looked up for the corresponding View. The class is ViewModelLocationProvider, in file ViewModelLocationProvider.cs you can use following methods to setup the 'view model factories'
/// <summary>
/// Sets the default view model factory.
/// </summary>
/// <param name="viewModelFactory">The view model factory which provides the ViewModel type as a parameter.</param>
public static void SetDefaultViewModelFactory(Func<Type, object> viewModelFactory)
{
_defaultViewModelFactory = viewModelFactory;
}
/// <summary>
/// Sets the default view model factory.
/// </summary>
/// <param name="viewModelFactory">The view model factory that provides the View instance and ViewModel type as parameters.</param>
public static void SetDefaultViewModelFactory(Func<object, Type, object> viewModelFactory)
{
_defaultViewModelFactoryWithViewParameter = viewModelFactory;
}
/// <summary>
/// Registers the view model factory for the specified view type name.
/// </summary>
/// <param name="viewTypeName">The name of the view type.</param>
/// <param name="factory">The viewmodel factory.</param>
public static void Register(string viewTypeName, Func<object> factory)
{
_factories[viewTypeName] = factory;
}
then all the logic for getting view model instance is in the following, pay attention to the comment summary here, it describes the logic/strategy
/// <summary>
/// Automatically looks up the viewmodel that corresponds to the current view, using two strategies:
/// It first looks to see if there is a mapping registered for that view, if not it will fallback to the convention based approach.
/// </summary>
/// <param name="view">The dependency object, typically a view.</param>
/// <param name="setDataContextCallback">The call back to use to create the binding between the View and ViewModel</param>
public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback)
{
// Try mappings first
object viewModel = GetViewModelForView(view);
// Fallback to convention based
if (viewModel == null)
{
var viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType());
if (viewModelType == null)
return;
viewModel = _defaultViewModelFactoryWithViewParameter != null ? _defaultViewModelFactoryWithViewParameter(view, viewModelType) : _defaultViewModelFactory(viewModelType);
}
setDataContextCallback(view, viewModel);
}
on line 87 and 96 you get you view model instance for the corresponding view.
So that means, if you don't call any of those methods to setup the factories, it will fall back to the default factory which is
/// <summary>
/// The default view model factory whic provides the ViewModel type as a parameter.
/// </summary>
static Func<Type, object> _defaultViewModelFactory = type => Activator.CreateInstance(type);
that is pretty clear you will always get a new instance.
Regarding Unity, I didn't see anything special, the only clue is that in the PrismApplication class in PrismApplication.cs, it sets up the factory like following:
/// <summary>
/// Configures the <see cref="ViewModelLocator"/> used by Prism.
/// </summary>
protected virtual void ConfigureViewModelLocator()
{
ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Resolve(type));
}
that means the factory is now using
/// <summary>
/// Resolves the specified type.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>A concrete instance of the specified type.</returns>
protected virtual object Resolve(Type type)
{
return Activator.CreateInstance(type);
}
which you can override with your own implementation.
In PrismUnityApplication class, PrismUnityApplication.cs, it offers a default implementation to resolve the instance with Unity
/// <summary>
/// Implements the Resolves method to be handled by the Unity Container.
/// Use the container to resolve types (e.g. ViewModels and Flyouts)
/// so their dependencies get injected
/// </summary>
/// <param name="type">The type.</param>
/// <returns>A concrete instance of the specified type.</returns>
protected override object Resolve(Type type)
{
return Container.Resolve(type);
}
and yeah, like other guys mentioned, you can control the lifetime of your view models yourself via Unity.
2) sorry for the long answer,
but I feel it's better to show you some code that will make things clear.
I'll keep the 2nd one short.
In my opinion, you don't need a view model when your view is gone.
I am not sure how the Frame stack is implemented in UWP and how they manage the view/page instances. I would assume once you navigate to a different page, the previous view/page should be released or can be released at GC, and you have the parameter and page type to be able to navigate back, but it will be a new instance and you restore the state of your view by restoring your view model.
so really, i think you're on the right track. and you should save/persist your user data whenever you can, and your solution works when the app is suspended and then is resumed, you can still recover the state of your view.
Thanks for reading.
It should be solved when you register your ViewModels as singletons (ContainerControlledLifetimeManager) in the UnityContainer. The best place for this would be the App.xaml.cs in method OnInitializeAsync
protected override Task OnInitializeAsync(IActivatedEventArgs args)
{
Container.RegisterType<MyViewModel>(new ContainerControlledLifetimeManager());
// rest of the method
}
I am using ChatJs in my asp.net webapplication with signalr adapter. How to show the online user from database on page load.As i am new to asp.net please guide me. thanks in advance
/// <summary>
/// This method is STUB. This will SIMULATE a database of users
/// </summary>
private static readonly List<DbUserStub> dbUsersStub = new List<DbUserStub>();
// <summary>
/// This method is STUB. In a normal situation, the user info would come from the database so this method wouldn't be necessary.
/// It's only necessary because this class is simulating the database
/// </summary>
/// <param name="newUser"></param>
public static void RegisterNewUser(DbUserStub newUser)
{
if (newUser == null) throw new ArgumentNullException("newUser");
dbUsersStub.Add(newUser);
}
Using vanilla MVC I can revalidate my model with TryValidateModel. The TryValidateModel method doesn't seem to be applicable to WebAPI. How can I revalidate my model when using WebAPI?
I know it has been a while since this has been asked, but the problem is still valid. Thus i thought i should share my solution to this problem.
I decided to implement the TryValidateModel(object model) myself, based on the implementation in the System.Web.Mvc.Controller.cs
The problem is that the mvc's TryValidateModel internally used their own HttpContext and ModelState. If you go and compaire the two, they are very similar....
The be able to use our own HttpContext there exists a HttpContextWrapper that can be used for that.
And Since we have to clear our model state, it doesn't really matter that we use a different type of ModelState , as long as we get the desired result, thus i create a new ModelState object from the correct type...
I did add the error to the ModelState of the controller and not to the model state to the newly created ModelState , This seems to work just fine for me :)
Here is my code, that i just added to the controller...
do not forget to import the library...
using System.Web.ModelBinding;
protected internal bool TryValidateModel(object model)
{
return TryValidateModel(model, null /* prefix */);
}
protected internal bool TryValidateModel(object model, string prefix)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
var t = new ModelBindingExecutionContext(new HttpContextWrapper(HttpContext.Current), new System.Web.ModelBinding.ModelStateDictionary());
foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, t).Validate(null))
{
ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
}
return ModelState.IsValid;
}
I don't know when was it added but now there is Validate method on api controller.
ApiController.Validate Method (TEntity)
https://msdn.microsoft.com/en-us/library/dn573258%28v=vs.118%29.aspx
Based from rik-vanmechelen original answer, here is my version that relies on the services container exposed by Web API.
/// <summary>
/// Tries to validate the model.
/// </summary>
/// <param name="model">The model.</param>
/// <returns>Whether the model is valid or not.</returns>
protected internal bool TryValidateModel(object model)
{
if (model == null)
{
throw new ArgumentNullException("model");
}
var metadataProvider = Configuration.Services.GetService<System.Web.Http.Metadata.ModelMetadataProvider>();
var validatorProviders = Configuration.Services.GetServices<System.Web.Http.Validation.ModelValidatorProvider>();
var metadata = metadataProvider.GetMetadataForType(() => model, model.GetType());
ModelState.Clear();
var modelValidators = metadata.GetValidators(validatorProviders);
foreach (var validationResult in modelValidators.SelectMany(v => v.Validate(metadata, null)))
{
ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
}
return ModelState.IsValid;
}
This uses the following simple extension methods to access the services :
/// <summary>
/// Services container extension methods.
/// </summary>
public static class ServicesContainerExtensions
{
/// <summary>
/// Gets the service.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <param name="services">The services.</param>
/// <returns>The service.</returns>
/// <exception cref="System.ArgumentNullException">services</exception>
public static TService GetService<TService>(this ServicesContainer services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
return (TService)((object)services.GetService(typeof(TService)));
}
/// <summary>
/// Gets the services.
/// </summary>
/// <typeparam name="TService">The type of the service.</typeparam>
/// <param name="services">The services.</param>
/// <returns>The services.</returns>
/// <exception cref="System.ArgumentNullException">services</exception>
public static IEnumerable<TService> GetServices<TService>(this ServicesContainer services)
{
if (services == null)
{
throw new ArgumentNullException("services");
}
return services.GetServices(typeof(TService)).Cast<TService>();
}
}
The advantage of using this method is that it reuses the MetadataProvider and ValidatorProvider(s) you have configured for your Web API application while the previous answer is retrieving the one configured in ASP.NET MVC.
ASP.NET MVC and WebAPI run through different pipelines.
Turns out TryValidateModel is not supported in WebAPI. There's a feature request over on CodePlex.
I have this code inside my edmx designer file:
#region Navigation Properties
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("EnviroModel", "FK_Whiteout_Field1", "Field")]
public Field Field
{
get
{
**return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Field>("EnviroModel.FK_Whiteout_Field1", "Field").Value;**
}
set
{
((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Field>("EnviroModel.FK_Whiteout_Field1", "Field").Value = value;
}
}
I am getting following error in get part:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.