Use Mapper.Initialize() for multiple mappings - asp.net

I use AutoMapper V.6.1.1 as a mapper in my ASP.Net project.
Before I had configuration as below:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<A, B>();
cfg.CreateMap<C, D>().ForMember(dest => dest.CityDesc, opt => opt.MapFrom(src => src.City));
});
var mapper = config.CreateMapper();
var var1= mapper.Map<B>(request);
var var2= mapper.Map<List<C>, List<D>>(result);
Now, I want to refactor the code, using Mapper.Initialize(). So I used:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<A, B>();
cfg.CreateMap<C, D>().ForMember(dest => dest.CityDesc, opt => opt.MapFrom(src => src.City));
});
var var1= Mapper.Map<B>(request);
var var2= Mapper.Map<List<C>, List<D>>(result);
I have an run time error:
Missing type map configuration or unsupported mapping. Mapping types: A-> B
Is there any problem with using multiple configurations in Mapper.Initialize? There is no error in the case that has one mapping in Initialize() body. How should I fix the error?

Maybe you have more than one Mapper.Initialize in your project while you should not have multiple Mapper.Initialize in your project else it will become override and you lost previous mapping configurations that you set by Mapper.Initialize. Now It is possible to get the error (Missing type map configuration or unsupported mapping.)
I recommend you to use AutoMapper.Profile. You can warp your mapping configurations in the form of grouped (in separated Profiles) then register all of theme by Mapper.Initialize at once ;)
Look at this example:
public class AB_Profile : Profile {
protected override void Configure() {
CreateMap<A, B>();
// CreateMap<A, B1>();
// CreateMap<A, B2>();
}
}
public class CD_Profile : Profile {
protected override void Configure() {
CreateMap<C, D>()
.ForMember(dest => dest.CityDesc, opt => opt.MapFrom(src => src.City));
}
}
Then initialize the Mapper using above Profiles:
Mapper.Initialize(cfg => {
cfg.AddProfile<AB_Profile >();
cfg.AddProfile<CD_Profile >();
});

Starting version 5 use this, as mentioned on their website...
public class OrganizationProfile : Profile
{
public OrganizationProfile()
{
CreateMap<Foo, FooDto>();
// Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
}
}
// How it was done in 4.x - as of 5.0 this is obsolete:
// public class OrganizationProfile : Profile
// {
// protected override void Configure()
// {
// CreateMap<Foo, FooDto>();
// }
// }
See Doc
Then initialize the mapping as...
Mapper.Initialize(cfg => {
cfg.CreateMap<Foo, Bar>();
cfg.AddProfile<OrganizationProfile>();
});

Related

Can I with fzaninotto/Faker generate doc / xls files?

Reading docs for laravel 9 site at
https://github.com/fzaninotto/Faker
I did not find if there is a way to generate doc(microsoft word) / xls(microsoft excel) files with this library ?
Maybe some other library ?
Thanks in advance!
Faker is using to generate simple data like sentences, email, phone etc. But you can use, for example maatwebsite/excel to make xlsx filling it with faker.
The simplest way to create doc file is to make html file with doc extension.
Update:
Keep in mind that maatwebsite/excel was built for Laravel framework, but there are other packages witch can be used independent from frameworks, for example XLSWriter
maatwebsite/excel
Laravel's factory to make User model
class UserFactory extends Factory
{
protected $model = User::class;
public function definition()
{
return [
'login' => '0'.$this->faker->numberBetween(70000000000, 80000000000),
'email' => $this->faker->unique()->safeEmail,
'lastname' => $this->faker->lastName,
'firstname' => $this->faker->firstNameMale,
'phone' => $this->faker->phoneNumber,
];
}
}
maatwebsite's export class (this one uses a collection as source)
use Maatwebsite\Excel\Concerns\FromCollection;
class UsersExport implements FromCollection
{
private $collection;
public function __construct($collection)
{
$this->collection = $collection;
}
public function collection()
{
return $this->collection;
}
}
Make xlsx file with 10 users uses laravel's seeder
class XlsSeeder extends Seeder
{
public function run()
{
$users = User::factory()
->count(10)
->make();
Excel::store(new UsersExport($users), 'users.xlsx');
}
}
XLSWriter
Wherever you need to create xlsx, you can write something like:
for($i = 0; $i < 10; $i++) {
$users[] = [
$faker->numberBetween(70000000000, 80000000000),
$faker->unique()->safeEmail,
$faker->lastName,
$faker->firstName,
$faker->phoneNumber,
];
}
$fileObject = new \Vtiful\Kernel\Excel([
'path' => './tests'
]);
$file = $fileObject->fileName('users.xlsx', 'sheet_one')
->header(['login', 'email', 'lastname', 'firstname', 'phone'])
->data($users);
$file->output();

How to pass a RenderFragement<object> Template to a Blazor component

I'm stucking on one special thing where I try to pass an object of RenderFragment to a dynamically generated component.
I considered this sample from Devexpress https://docs.devexpress.com/Blazor/401753/common-concepts/customize-and-reuse-components
<DxFormLayout>
<DxFormLayoutTabPages>
#renderLayoutTabPage()
</DxFormLayoutTabPages>
</DxFormLayout>
#code {
private RenderFragment renderLayoutTabPage() {
RenderFragment item = b => {
b.OpenComponent<DxFormLayoutTabPage>(0);
b.AddAttribute(1, "Caption", "My tab");
b.AddAttribute(2, "ChildContent", (RenderFragment)((tabPageBuilder) => {
tabPageBuilder.OpenComponent<DxFormLayoutItem>(0);
tabPageBuilder.AddAttribute(1, "Caption", "DynLayoutItem");
tabPageBuilder.AddAttribute(2, "ColSpanMd", 6);
tabPageBuilder.AddAttribute(5, "Template", (RenderFragment<Object>)((context) => ((itemTemplate) => {
itemTemplate.OpenComponent<DxTextBox>(0);
itemTemplate.AddAttribute(1, "Text", text);
itemTemplate.CloseComponent();
})));
tabPageBuilder.CloseComponent();
}));
b.CloseComponent();
};
return item;
}
}
So this is the way they are building a complete new ChildContent Fragment.
my razor file looks like:
[Parameter] RenderFragment<object> DisplayTemplate {get;set;} //pass this Fragement to the dynamic component
protected override void OnInitialized()
{
...
b.AddAttribute(3, nameof(DxDataGridColumn.DisplayTemplate), (RenderFragment<Object>)((context) => ((itemTemplate) =>
{
itemTemplate.AddContent<object>(0, DisplayTemplate, context);
})));
...
}
When I run this, the DisplayTemplate does not get rendered. I only can see the type string "Microsoft.AspNetCore.Components.RenderFragment`1[System.Object]"
What I'm doing wrong here?
Got it!
In my Component I was using this pattern
<MyComponent>
<DisplayTemplate>
#DisplayTemplate
</DisplayTemplate>
<MyComponent>
The only way it works correct is to use the Attributes directly:
<MyComponent DisplayTemplate"#DisplayTemplate" />

ObservableChangeSet wait until list is ready before watching

We have a list page where we can enable or disable a thing™ using a <switch /> That thing™ is toggled with an IsActive flag
public class Thing
{
/* ... */
[Reactive] public bool IsActive { get; set; }
}
Given the following change listener, the idea is when the IsActive property changes (user interaction on a toggle switch), we invoke the _saveItemCommand to save the entity with the new IsActiveState.
public ObservableCollection<Thing> DataObjectList {get;} = new ObservableCollection<Thing>();
public MyClass()
{
_saveItemCommand = ReactiveCommand.CreateFromTask(SaveItemInternal);
_listWatcher = DataObjectList
.ToObservableChangeSet()
.AsObservableList()
.Connect()
.WhenPropertyChanged(x => x.IsActive)
.Throttle(TimeSpan.FromMilliseconds(250))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(x => x.Sender)
.InvokeCommand(_saveItemCommand);
}
public void OnNavigatingTo()
{
var newItems = _myService.GetNewItems();
DataObjectList.AddRange(newItems);
}
public void OnDestroy()
{
_listWatcher?.Dispose();
}
The problem I'm having is that when I setup the list, The command seems to be invoked on the last item in the list immediately after AddRange is called.
I have tried using .Skip(1) without any luck, but one thing that seems to work but is ugly is .Skip(DataObjectList.Length)
How can I make it so that the command isn't invoked until the first time the user toggles the switch? What is the correct way to setup this listener?
Most likely you'll want to add a Where statement to indicate it should only be called on the IsActivated switch.
_listWatcher = DataObjectList
.ToObservableChangeSet()
.AsObservableList()
.Connect()
.WhenPropertyChanged(x => x.IsActive)
.Throttle(TimeSpan.FromMilliseconds(250))
.ToCollection()
.Where(x => x.Any(value => value.IsActive))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(x => x.Sender)
.InvokeCommand(_saveItemCommand);
So the two lines I added are
.ToCollection()
.Where(x => x.Any(value => value.IsActive))
The ToCollection() will convert it into an observable list and the Where will restrict your observable to when there is change of the IsActive values.
You may wish to add a FirstAsync() call if you want it to happen only once after the Where() call.
After the comments on Glenn's answer and some additional conversations with Rodney, here's what finally works.
_listWatcher = DataObjectList
.ToObservableChangeSet()
.AsObservableList()
.Connect()
.WhenPropertyChanged(x => x.IsActive)
.Throttle(TimeSpan.FromMilliseconds(250))
.Skip(1)
.DistinctUntilChanged()
.ObserveOn(RxApp.MainThreadScheduler)
.Select(x => x.Sender)
.InvokeCommand(_createActivationsInternal);

How to translate $url_handlers?

I have a situation where I need to translate the following $url_handlers for different countries.
So on an english site the URL looks like this: http://website.com/gyms/boston/group-training
I need to be able to translate the "group-training" part of the URL. I have translated the rest of the site using the _t() method throughout.
My current setup:
class GymLocationPage_Controller extends Page_Controller {
private static $allowed_actions = array(
'currentSpecials',
'sevenDayFreeTrial',
'groupTraining'
);
private static $url_handlers = array(
'current-specials' => 'currentSpecials',
'trial' => 'sevenDayFreeTrial',
'group-training' => 'groupTraining'
);
}
How would one achieve this?
You could update the config inside the controller's init() function, doing something like this:
public function init() {
parent::init();
// Define your translated actions.
$translatedCurrentSpecials = _t('Actions.CURRENT_SPECIALS', 'aktuella-kampanjer');
$translatedSevenDayFreeTrial = _t('Actions.SEVEN_DAY_TRIAL', 'sjudagars-prova-pa-period');
// Define your url handlers.
$urlHandlers = $this->config()->url_handlers;
$translatedUrlHandlers = [
$translatedCurrentSpecials => 'currentSpecials',
$translatedSevenDayFreeTrial => 'sevenDayFreeTrial'
];
// Update the config.
Config::inst()->update(
$this->class,
'url_handlers',
$translatedUrlHandlers + $urlHandlers // Important to prepend and not append.
);
}

GraphDiff: "Cascading" Owned Collections

I'm trying to use GraphDiff (latest available version in NuGet) to handle what I consider a not terribly difficult entity model. Consider a model like so:
class A
{
public virtual ICollection<B> Bs { get; set; }
}
class B
{
public virtual ICollection<C> Cs { get; set; }
}
If I'm updating an instance of A (call it aEntity), I could do:
context.UpdateGraph(aEntity, map =>
map.OwnedCollection(a => a.Bs, withB =>
withB.OwnedCollection(b => b.Cs)))
Now I'd also, sometimes, like to update B's independently.
context.UpdateGraph(bEntity, map => map.OwnedCollection(b => b.Cs));
So I figured I could "cascade" the changes by introducing a property, like so:
class BMapper {
Expression<Func<IUpdateConfiguration<B>, object>> MappingExpression
{
get
{
return map => map.OwnedCollection(b => b.Cs);
}
}
}
... and then use that in both scenarios like so:
// Update an A and any of its B's
context.UpdateGraph(aEntity, map =>
map.OwnedCollection(a => a.Bs, (new BMapper()).MappingExpression))
// Update a B by itself
context.UpdateGraph(bEntity, (new BMapper()).MappingExpression);
Updating the B by itself works fine, but updating an A falls down in expression land:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'string' does not contain a definition for 'Body'
Is there a way to share mappings in GraphDiff?

Resources