Using Castle.DynamicProxy, what is the best way to create a proxy from an existing class instance?
// The actual object
Person steve = new Person() { Name = "Steve" };
// Create a proxy of the object
Person fakeSteve = _proxyGenerator.CreateClassProxyWithTarget<Person>(steve, interceptor)
// fakeSteve now has steve as target, but its properties are still null...
Here's the Person class:
public class Person
{
public virtual string Name { get; set; }
}
Here's the interceptor class:
public class PersonInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Person p = invocation.InvocationTarget as Person;
if (invocation.Method.Name.Equals(get_Name)
{
LoadName(p);
}
}
private void LoadName(Person p)
{
if (string.IsNullOrEmpty(p.Name))
{
p.Name = "FakeSteve";
}
}
}
If your Person class has only non-virtual properties the proxy can't access them. Try to make the properties virtual.
http://kozmic.net/2009/02/23/castle-dynamic-proxy-tutorial-part-vi-handling-non-virtual-methods/
Related
I am trying to instantiate an object of my model class, from my MVVM test project, in my viewmodel class.
Person Model Class:
using System.ComponentModel;
namespace WPFAppTest.Models
{
public class Person : INotifyPropertyChanged
{
private string _FirstName;
public string FirstName
{
get
{
return _FirstName;
}
set
{
_FirstName = value;
RaisePropertyChange("FirstName");
RaisePropertyChange("FullName");
}
}
private string _LastName;
public string LastName
{
get
{
return _LastName;
}
set
{
_LastName = value;
RaisePropertyChange("LastName");
RaisePropertyChange("FullName");
}
}
public string FullName
{
get
{
return _FirstName + " " + _LastName;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChange(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
PersonViewModel Class:
using WPFAppTest.Models;
namespace WPFAppTest.ViewModels
{
public class PersonViewModel
{
public Person person = new Person();
person.FirstName = "Iain";
}
}
It seems I get an error saying "The name 'person.FirstName' does not exist in the current context".
How do I create the object and then access its properties to set the values? Which in turn I can then use for data bindings in my View?
The statement person.FirstName = "Iain"; must be inside a method or in the constructor
public class PersonViewModel
{
public Person person = new Person();
public PersonViewModel() // constructor
{
person.FirstName = "Iain";
}
public void Test() // method
{
person.FirstName = "Pete";
}
}
Note: the constructor which is called automatically when you create an object with new PersonViewModel() has the same name as the class and does not have a return type (there is no void keyword).
The method Test must be called explicitly
var p = new PersonViewModel(); // calls constructor and assigns "Iain".
p.Test(); // Assigns "Pete"
The constructor can have parameters like a method.
public PersonViewModel(string personName) // constructor with parameter
{
person.FirstName = personName;
}
You must pass an argument to this parameter when calling new:
var p = new PersonViewModel("Sue"); // Creates a VM with a person named "Sue".
For a View Model it would probably make sense to pass a Person instead.
public class PersonViewModel
{
private readonly Person _person;
public string FirstName => _person.FirstName;
public PersonViewModel(Person person) // constructor
{
_person = person;
}
}
I was not able to find an answer to this because I didn't know how to put it.
I have a class Car() and a class Owner(). What I need is to have an object of 'owner', as a simple attribute of my Car() class, so I can pass it as a argument once I instanciate my Car() object.
My Owner() Class:
class Owner
{
public Owner(string address){
this.address = address;
}
}
My Car() Class:
class Car
{
public Car(object owner){ // what type to use?
this.owner = owner;
}
private object owner; // what type to use?
}
And my Main() Class:
static void Main(string[] args){
Owner owner1 = new Owner("street foo city bar");
Car car1 = new Car(owner1); // this needs to work
}
Obviously, using the 'object' type for the attribute didn't do it. Once I print I get 'myProjectName.Owner'. Thank you in advance.
You can write your code as below, writing public methods to return the objects you want.
class Program
{
static void Main(string[] args)
{
Owner owner1 = new Owner("street foo city bar");
Car car1 = new Car(owner1); // this needs to work
Console.WriteLine("Car 1 owner address : " + car1.getOwner().getAddress());
Console.ReadKey();
}
}
class Car
{
private Owner owner; // same here\
public Car(Owner owner)
{ // use Owner class
this.owner = owner;
}
public Owner getOwner() // write a public method to return owner
{
return this.owner;
}
}
class Owner
{
private string address; // this
public Owner(string address)
{
this.address = address;
}
public string getAddress() // write a public method to return address
{
return this.address;
}
}
public class Car
{
public Car(Owner owner)
{
this.Owner = owner;
}
//Since Owner is public, you don't have to create a getter method for this. i.e GetOwner()
public Owner Owner;
}
public class Owner
{
//Since address is private, you'll have to create a public getter for this
private string address;
public Owner(string address)
{
this.address = address;
}
//public getter for the address
public string GetAddress()
{
return this.address;
}
}
public class Main
{
static void main(string[] args)
{
Owner owner1 = new Owner("street address");
Car car1 = new Car(owner1);
car1.Owner.GetAddress();
}
}
I created substitutes for Person and AddressBook classes in the unit Test.
The AddressBook class contains properties of type Person and name: SamplePerson.
public interface IAddressBook
{
Person SamplePerson { get; set; }
}
public class AddressBook : IAddressBook
{
public Person SamplePerson { get; set; }
public AddressBook(Person samplePerson)
{
SamplePerson = samplePerson;
}
}
public interface IPerson
{
string GetName(string name);
}
public class Person : IPerson
{
public string GetName(string name)
{
return name;
}
}
public void TestMethod1()
{
var personMock = Substitute.For<IPerson>();
var addressBookMock = Substitute.For<IAddressBook>();
addressBookMock.SamplePerson.Returns(personMock); //not working
addressBookMock.SamplePerson = personMock; //not working
addressBookMock.SamplePerson = (Person)personMock; //not working
Assert.AreEqual(1, 1);
}
I would like to assign mock variable of Person type to propeties of mock variable of type AddressBook.
Is this possible?
IAddressBook.SamplePerson property returns Person implementation and not IPerson interface, so your attempt to return IPerson will not work.
Either mock the Person class
var personMock = Substitute.For<Person>();
var addressBookMock = Substitute.For<IAddressBook>();
addressBookMock.SamplePerson.Returns(personMock);
or return an actual instance.
var person = new Person();
var addressBookMock = Substitute.For<IAddressBook>();
addressBookMock.SamplePerson.Returns(person);
I have these classes:
public interface IPerson
{
string Name { get; set; }
}
public class Person : IPerson
{
public string Name { get; set; }
}
public interface IRoom
{
List<Furniture> Furnitures { get; set; }
List<Person> People { get; set; }
}
public class Room : IRoom
{
public List<Furniture> Furnitures { get; set; }
public List<Person> People { get; set; }
}
public enum Furniture
{
Table,
Chair
}
And I have this extension method:
public static void Assign<T>(this IRoom sender, Func<IRoom,ICollection<T>> property, T value)
{
// How do I actually add a Chair to the List<Furniture>?
}
And I want to use it like this:
var room = new Room();
room.Assign(x => x.Furnitures, Furniture.Chair);
room.Assign(x => x.People, new Person() { Name = "Joe" });
But I have no idea how to add T to ICollection<T>.
Trying to learn generics and delegates. I know room.Furnitures.Add(Furniture.Chair) works better :)
public static void Assign<T>(this IRoom room, Func<IRoom, ICollection<T>> collectionSelector, T itemToAdd)
{
collectionSelector(room).Add(itemToAdd);
}
You don't need a Func<IRoom,ICollection<T>> here. This takes room as argument and returns ICollection<T>. ICollection<T> as a parameter is enough. Let's rewrite your code as following to make it work.
public static void Assign<T>(this IRoom sender, ICollection<T> collection, T value)
{
collection.Add(value);
}
Then call it as
room.Assign(room.Furnitures, Furniture.Chair);
room.Assign(room.People, new Person() { Name = "Joe" });
If you're not satisfied with this approach and you need your own approach only then try the following
public static void Assign<T>(this IRoom sender, Func<IRoom, ICollection<T>> property, T value)
{
property(sender).Add(value);
}
Then call it with your own syntax should work
room.Assign(x => x.Furnitures, Furniture.Chair);
room.Assign(x => x.People, new Person() { Name = "Joe" });
Note:Keep in mind you've not initialized your collections, this will result in NullReferenceException, so to get rid of it add a contructor in your Room class as follows
public Room()
{
Furnitures = new List<Furniture>();
People = new List<Person>();
}
I am trying to make a binder for an abstract class. The binder decides which implementation of the class to use.
public abstract class Pet
{
public string name { get; set; }
public string species { get; set; }
abstract public string talk { get; }
}
public class Dog : Pet
{
override public string talk { get { return "Bark!"; } }
}
public class Cat : Pet
{
override public string talk { get { return "Miaow."; } }
}
public class Livestock : Pet
{
override public string talk { get { return "Mooo. Mooo. Fear me."; } }
}
So I have a controller which takes a Pet, the binder decides (depending on the species string) if it is a Dog, Cat or Livestock.
public class PetBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var values = (ValueProviderCollection)bindingContext.ValueProvider;
var name = (string)values.GetValue("name").ConvertTo(typeof(string));
var species = (string)values.GetValue("species").ConvertTo(typeof(string));
if (species == "dog")
{
return new Dog { name = name, species = "dog" };
}
else if (species == "cat")
{
return new Cat { name = name, species = "cat" };
}
else
{
return new Livestock { name = name, species = species };
}
}
}
public class HomeController : Controller
{
public JsonResult WorksFine(Pet pet)
{
return Json(pet);
}
public JsonResult DoesntWork(List<Pet> pets)
{
return Json(pets);
}
}
This works well, but as soon as the pet is in another structure (like List<Pet> or another object), I get a NullReferenceException (on the line var name = (string)values.GetValue("name").ConvertTo(typeof(string));
in the PetBinder). What am I doing wrong?
I added a Person class to test. It also gave me a NullReferenceException.
public class Person
{
public string name { get; set; }
public Pet pet { get; set; }
}
public class HomeController : Controller
{
public JsonResult PersonAction(Person p)
{
return Json(p);
}
}
ccurrens said the reason var name = (string)values.GetValue("name").ConvertTo(typeof(string));
returned null was because it couldn't get the values from a list.
I see they are named [n].name and [n].species when in a List<Pet>, but when in the Person object they are named pet.name and pet.species and when they are in a single Pet, they are just named name and species.
Solution
To get the parameter names with the right prefix ([n] or pet or anything else) for GetValue, I used the following code:
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";
If anyone is interested, I ended up inheriting from DefaultModelBinder using something similar to this answer. Here is the full code I used:
public class DefaultPetBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)
{
//https://stackoverflow.com/questions/5460081/asp-net-mvc-3-defaultmodelbinder-inheritance-problem
bool hasPrefix = bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName);
string prefix = ((hasPrefix)&&(bindingContext.ModelName!="")) ? bindingContext.ModelName + "." : "";
// get the parameter species
ValueProviderResult result;
result = bindingContext.ValueProvider.GetValue(prefix+"species");
if (result.AttemptedValue.Equals("cat"))
return base.CreateModel(controllerContext,bindingContext,typeof(Cat));
else if (result.AttemptedValue.Equals("dog"))
return base.CreateModel(controllerContext,bindingContext,typeof(Dog));
return base.CreateModel(controllerContext, bindingContext, typeof(Livestock)); // livestock
}
}
In the line you're getting your error, values could be null or what GetValue("name") returns could be null.
I'm assuming when you're calling the List<Pet> method, ValueProvider is returning the entire List instead of each individual Pet, so it can't get the value "name" since it doesn't exist in the List class.
I can't be more sure without seeing more code.