Building a ViewModel - mvvm-light

Greetings,
I have a ViewModel for a ProductCategory.
The ProductCategory has a boolean Active field.
Is is possible to have a single ProductCategoryViewModel and be able to get a collection of all ProductCategories and a collection of ACTIVE ProductCategories?
Or, would I have to create an ActiveProductCategoryViewModel?
I'm using MVVM-Light with RIA in Silverlight...so, I have a ProductCategory service with a GetProductCategories method and a GetActiveProductCategories method. I want to be able to get the ActiveProductCategories to populate a dropdown...but also get ALL the ProductCategories for maintenance and historical purposes etc.
Thanks!
Butcher

I assume you have another ViewModel with a collection of ProductCategoryViewModel objects? If so, I think its fine to have another collection of just the active product categories. I'm not sure you need a separate service method for this, since you can just filter your collection of product categories based on the Active value.
If this view model would be called ProductCategoriesViewModel, it might look like this:
using System.Collections.Generic;
using System.Linq;
using GalaSoft.MvvmLight;
namespace OCEAN.EPP.ViewModel
{
public class ProductCategoriesViewModel : ViewModelBase
{
public ProductCategoriesViewModel()
{
if (IsInDesignMode)
{
ProductCategories = new List<ProductCategoryViewModel>
{
new ProductCategoryViewModel { Active = false },
new ProductCategoryViewModel { Active = false },
new ProductCategoryViewModel { Active = true },
new ProductCategoryViewModel { Active = true },
};
}
else
{
// Code runs "for real": Connect to service, etc...
}
}
public const string ProductCategoriesPropertyName = "ProductCategories";
private List<ProductCategoryViewModel> _productCategories = new List<ProductCategoryViewModel>();
public List<ProductCategoryViewModel> ProductCategories
{
get { return _productCategories; }
set
{
if (_productCategories == value)
return;
_productCategories = value;
FilterActiveProductCategories();
RaisePropertyChanged(ProductCategoriesPropertyName);
}
}
public const string ActiveProductCategoriesPropertyName = "ActiveProductCategories";
private List<ProductCategoryViewModel> _activeProductCategories = new List<ProductCategoryViewModel>();
public List<ProductCategoryViewModel> ActiveProductCategories
{
get { return _activeProductCategories; }
set
{
if (_activeProductCategories == value)
return;
_activeProductCategories = value;
RaisePropertyChanged(ActiveProductCategoriesPropertyName);
}
}
private void FilterActiveProductCategories()
{
ActiveProductCategories = ProductCategories.Where(pc => pc.Active).ToList();
}
}
}

Related

Extending existing ABP controllers

I am using version 3.3.2 of the ABP Framework. How can I add new methods to an existing controller? I want to extend the IdentityUserController. Following the docs I am creating my own implementation as following:
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IdentityUserController))]
public class MyIdentityUserController : IdentityUserController
{
public MyIdentityUserController(IIdentityUserAppService userAppService) : base(userAppService)
{
}
public override Task<PagedResultDto<IdentityUserDto>> GetListAsync(GetIdentityUsersInput input)
{
return base.GetListAsync(input);
}
[HttpGet]
[Route("my-method")]
public Task<string> MyMethod()
{
return Task.FromResult("Works");
}
}
The overrides actually work but my custom method is not visible in Swagger and when I try to access it with Postman it is not accessible either. Any ideas how I can extend existing controllers? I don't want to create a whole new controller since I have a combination with overrides and new methods. I would like to keep everything together.
First, set IncludeSelf = true — we will use this to determine whether to replace the existing controller with the extended controller, and ASP.NET Core will resolve your controller by class.
Optionally, add [ControllerName("User")] from IdentityUserController since it is not inherited:
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IdentityUserController), IncludeSelf = true)]
[ControllerName("User")]
public class MyIdentityUserController : IdentityUserController
Option 1
Subclass AbpServiceConvention and override RemoveDuplicateControllers to remove the existing controller(s) instead of your extended controller:
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf)
{
var existingControllerModels = application.Controllers
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray();
derivedControllerModels.AddRange(existingControllerModels);
Logger.LogInformation($"Removing the controller{(existingControllerModels.Length > 1 ? "s" : "")} {exposeServicesAttr.ServiceTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")} from the application model since {(existingControllerModels.Length > 1 ? "they are" : "it is")} replaced by the controller: {controllerModel.ControllerType.AssemblyQualifiedName}");
continue;
}
Full code of subclass:
public class MyAbpServiceConvention : AbpServiceConvention
{
public MyAbpServiceConvention(
IOptions<AbpAspNetCoreMvcOptions> options,
IConventionalRouteBuilder conventionalRouteBuilder)
: base(options, conventionalRouteBuilder)
{
}
protected override void RemoveDuplicateControllers(ApplicationModel application)
{
var derivedControllerModels = new List<ControllerModel>();
foreach (var controllerModel in application.Controllers)
{
if (!controllerModel.ControllerType.IsDefined(typeof(ExposeServicesAttribute), false))
{
continue;
}
if (Options.IgnoredControllersOnModelExclusion.Contains(controllerModel.ControllerType))
{
continue;
}
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr.IncludeSelf)
{
var existingControllerModels = application.Controllers
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType))
.ToArray();
derivedControllerModels.AddRange(existingControllerModels);
Logger.LogInformation($"Removing the controller{(existingControllerModels.Length > 1 ? "s" : "")} {exposeServicesAttr.ServiceTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")} from the application model since {(existingControllerModels.Length > 1 ? "they are" : "it is")} replaced by the controller: {controllerModel.ControllerType.AssemblyQualifiedName}");
continue;
}
var baseControllerTypes = controllerModel.ControllerType
.GetBaseClasses(typeof(Controller), includeObject: false)
.Where(t => !t.IsAbstract)
.ToArray();
if (baseControllerTypes.Length > 0)
{
derivedControllerModels.Add(controllerModel);
Logger.LogInformation($"Removing the controller {controllerModel.ControllerType.AssemblyQualifiedName} from the application model since it replaces the controller(s): {baseControllerTypes.Select(c => c.AssemblyQualifiedName).JoinAsString(", ")}");
}
}
application.Controllers.RemoveAll(derivedControllerModels);
}
}
Option 2
Implement IApplicationModelConvention to add your extended controller to IgnoredControllersOnModelExclusion and remove the existing controller:
public class ExtendedControllerApplicationModelConvention : IApplicationModelConvention
{
private readonly Lazy<IOptions<AbpAspNetCoreMvcOptions>> _lazyOptions;
public ExtendedControllerApplicationModelConvention (IServiceCollection services)
{
_lazyOptions = services.GetRequiredServiceLazy<IOptions<AbpAspNetCoreMvcOptions>>();
}
public void Apply(ApplicationModel application)
{
var controllerModelsToRemove = new List<ControllerModel>();
var ignoredControllersOnModelExclusion = _lazyOptions.Value.Value.IgnoredControllersOnModelExclusion;
foreach (var controllerModel in application.Controllers)
{
var exposeServicesAttr = ReflectionHelper.GetSingleAttributeOrDefault<ExposeServicesAttribute>(controllerModel.ControllerType);
if (exposeServicesAttr != null && exposeServicesAttr.IncludeSelf)
{
ignoredControllersOnModelExclusion.AddIfNotContains(controllerModel.ControllerType);
var existingControllerModels = application.Controllers
.Where(cm => exposeServicesAttr.ServiceTypes.Contains(cm.ControllerType));
controllerModelsToRemove.AddIfNotContains(existingControllerModels);
}
}
application.Controllers.RemoveAll(controllerModelsToRemove);
}
}
In your module, insert ExtendedServiceApplicationModelConvention before AbpServiceConventionWrapper:
public override void ConfigureServices(ServiceConfigurationContext context)
{
// ...
Configure<MvcOptions>(options =>
{
var abpServiceConvention = options.Conventions.OfType<AbpServiceConventionWrapper>().First();
options.Conventions.InsertBefore(abpServiceConvention, new ExtendedControllerApplicationModelConvention (context.Services));
});
}
I created a test project using the same version of ABP v3.3.2 and managed to get this working.
You can override the original methods in a new class that inherits from the original IdentityUserController, but you need to create your own controller to 'add' new methods to it. If you create a new controller that includes the same class attributes as IdentityUserController then it will appear like it has been extended.
[RemoteService(Name = IdentityRemoteServiceConsts.RemoteServiceName)]
[Area("identity")]
[ControllerName("User")]
[Route("api/identity/users")]
[ExposeServices(typeof(MyIdentityUserController))]
public class MyIdentityUserController : AbpController, IApplicationService, IRemoteService
{
[HttpGet("my-method")]
public Task<string> MyMethod()
{
return Task.FromResult("Works");
}
}

How to add Mock db tables in C# test cases

How to create mock db tables for the separate class file in test cases to access the service test case and also I need for that tables between parent and child relation
public static class MockTestData
{
// Test data for the DbSet<User> getter
public static IQueryable<EaepTieriiLangComp> Langcomps
{
get
{ return new List<EaepTieriiLangComp>
{
new EaepTieriiLangComp{EaepAssessmentId=1,LangCompId=1,IsPrimary ="Y",LangId =1,LangReadId=1,LangWrittenId=1,LangSpokenId=1,LangUnderstandId=1 },
new EaepTieriiLangComp{EaepAssessmentId=2,LangCompId=1 ,IsPrimary ="N",LangId =2,LangReadId=2,LangWrittenId=2,LangSpokenId=2,LangUnderstandId=2 }//Lang =obj,LangRead=objRead,LangSpoken =objSpeak,LangWritten=objWrite,LangUnderstand=objUnderstand
}.AsQueryable();
}
}
public static IQueryable<LookupLang> LookupLangs
{
get
{ return new List<LookupLang>
{
new LookupLang{LangId = 1,Description = "lang1",IsActive="Y"},
new LookupLang{LangId = 2,Description = "lang2",IsActive="N"}
}.AsQueryable();
}
}
}`
enter code here`
I tried for the above flow but i didnot get relatons for that tables
If you are using EF Core, you can create inmemory database, add data and make query to it.
Here is example:
First you need install Microsoft.EntityFrameworkCore.InMemory package. After this make options:
_options = new DbContextOptionsBuilder<SomeDbContext>()
.UseInMemoryDatabase(databaseName: "DbTest")
.Options;
using var context = new SomeDbContext(_options);
context.Database.EnsureCreated();
Then add your data:
context.AddRange(
new LookupLang{LangId = 1,Description = "lang1",IsActive="Y"},
new LookupLang{LangId = 2,Description = "lang2",IsActive="N"}
)
And now you can use context for testing purposes
Thank you so much advise to use EF core.InMemory package it is working fine now I followed below code
Inmemory class
using Assessments.TierIIQueryDataModel;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace AssessmentCommandTest.Helpers
{
public class InMemoryDataProviderQueryService : IDisposable
{
private bool disposedValue = false; // To detect redundant calls
public DbQueryContext CreateContextForInMemory()
{
var option = new DbContextOptionsBuilder<DbQueryContext>().UseInMemoryDatabase(databaseName: "Test_QueryDatabase").Options;
var context = new DbQueryContext(option);
if (context != null)
{
//context.Database.EnsureDeleted();
context.Database.EnsureCreated();
}
return context;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
}
and access to DbQueryContext conext file in my code and write mock tables as below
using AssessmentCommandTest.Helpers;
using Assessments.TierIIQueryDataModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssessmentCommandTest.MockDbTables
{
public class MockQueryDbContext
{
public TierIIQueryContext MockTierIIQueryContexts()
{
//Create object for Inmemory DB provider
var factory = new InMemoryDataProviderQueryService();
//Get the instance of TierIIQueryContext
var context = factory.CreateContextForInMemory();
context.LookupLang.Add(new LookupLang { LangId = 1, Description = "Arabic", IsActive = "Y" });
context.LookupLang.Add(new LookupLang { LangId = 2, Description = "Bangali", IsActive = "Y" });
context.LookupLang.Add(new LookupLang { LangId = 3, Description = "English", IsActive = "Y" });
context.LookupLang.Add(new LookupLang { LangId = 4, Description = "French", IsActive = "Y" });
enter code here
context.SaveChanges();
return context;
}
}
}

Strangeness with DataContext and GridView / ListView

I have a Windows 8 store app based off of the grouped template project, with some renames etc. However, I'm having a hard time getting the ItemsSource databinding to work for both non-snapped and snapped visual states.
I have a property, that, when set, changes the ItemsSource property, but I can only get one of the controls to bind at a time (either the GridView for non-snapped, or the ListView for snapped).
When I use the following, only the non-snapped binding works and the snapped binding shows no items:
protected PickLeafModel ListViewModel
{
get
{
return (PickLeafModel)m_itemGridView.ItemsSource;
}
set
{
m_itemGridView.ItemsSource = value;
m_snappedListView.ItemsSource = value;
}
}
If I comment out one of the setters, the snapped view shows items but the non-snapped view shows nothing:
protected PickLeafModel ListViewModel
{
get
{
return (PickLeafModel)m_itemGridView.ItemsSource;
}
set
{
//m_itemGridView.ItemsSource = value;
m_snappedListView.ItemsSource = value;
}
}
It's as if I can bind my view model only to one property at a time. What am I doing wrong?
Since I am generating my data model on another thread (yes, using the thread pool), I cannot make it inherit from DependencyObject. If I do, I get a WrongThreadException.
So to make it work I have done the following:
public class PickLeafModel : IEnumerable
{
public PickLeafModel()
{
}
public IEnumerator GetEnumerator()
{
if (m_enumerator == null)
{
m_enumerator = new PickLeafModelViewDataEnumerator(m_data, m_parentLeaf);
}
return m_enumerator;
}
private SerializableLinkedList<PickLeaf> m_data =
new SerializableLinkedList<PickLeaf>();
}
and then my items look like this:
// Augments pick leafs by returning them wrapped with PickLeafViewData.
class PickLeafModelViewDataEnumerator : IEnumerator
{
public PickLeafModelViewDataEnumerator(
SerializableLinkedList<PickLeaf> data, PickLeaf parentLeaf)
{
m_viewDataList =
new System.Collections.Generic.LinkedList<PickLeafViewData>();
foreach (PickLeaf leaf in data)
{
PickLeafViewData viewData = new PickLeafViewData();
viewData.copyFromPickLeaf(leaf, parentLeaf);
m_viewDataList.AddLast(viewData);
}
m_enumerator = m_viewDataList.GetEnumerator();
}
public void Dispose()
{
m_viewDataList = null;
m_enumerator = null;
}
public object Current
{
get
{
return m_enumerator.Current;
}
}
public bool MoveNext()
{
return m_enumerator.MoveNext();
}
public void Reset()
{
m_enumerator.Reset();
}
private IEnumerator<PickLeafViewData> m_enumerator = null;
private System.Collections.Generic.LinkedList<PickLeafViewData>
m_viewDataList;
}
}
Is there something I'm doing fundamentally wrong?
Help appreciated.
Thanks!
Thankfully there is a much easier way to do what you are trying!
Create a class called your ViewModel as shown below:
public class DataViewModel
{
public DataViewModel()
{
Data = new ObservableCollection<PickLeafViewData>(new PickLeafModelViewDataEnumerator(m_data, m_parentLeaf));
}
public ObservableCollection<PickLeafViewData> Data
{
get;
set;
}
}
Now on the code behind set the Page.DataConected to equal an instance of the above class.
And finally on both your snapped listview, and the grid view set the item source to this:-
ItemsSource="{Binding Data}"
That should work nicely for you.
Thanks to Ross for pointing me in the right direction.
I'm not 100% happy with this solution, but it does work. Basically the idea is that after I get back the PickLeafModel from the worker threads, I transplant its internal data into a derived version of the class which is data binding aware.
public class PickLeafViewModel : PickLeafModel, IEnumerable
{
public PickLeafViewModel()
{
}
public PickLeafViewModel(PickLeafModel model)
{
SetData(model);
}
public void SetData(PickLeafModel model)
{
model.swap(this);
}
public IEnumerator GetEnumerator()
{
if (m_observableData == null)
{
m_observableData = new ObservableCollection<PickLeafViewData>();
var data = getData();
PickLeaf parentLeaf = getParentLeaf();
foreach (PickLeaf leaf in data)
{
PickLeafViewData viewData = new PickLeafViewData();
viewData.copyFromPickLeaf(leaf, parentLeaf);
m_observableData.Add(viewData);
}
}
return m_observableData.GetEnumerator();
}
and the page code is as follows:
protected PickLeafViewModel ListViewModel
{
get
{
return DataContext as PickLeafViewModel;
}
set
{
DataContext = value;
}
}
whenever I want to set ListViewModel, I can do this:
ListViewModel = new PickLeafViewModel(model);
and swap looks like:
private static void swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
// Swaps internals with the other model.
public void swap(PickLeafModel other)
{
swap(ref m_data, ref other.m_data);
...
Also, PickLeafModelViewDataEnumerator can be deleted altogether.

Enable Always on Top For Caliburn Managed Window

I have the following ViewModel and I am using Caliburn Micro. The IWindowManager instance is properly resolved and all of the code works. As indicated by the TODO comment, I need to get a reference to the current window so I can toggle the AlwaysOnTop attribute. How can I do that?
namespace CaliburnWizardPlay
{
[Export(typeof(DropWindowViewModel))]
public class DropWindowViewModel : PropertyChangedBase, IHaveDisplayName
{
private readonly IWindowManager windowManager;
[ImportingConstructor]
public DropWindowViewModel(IWindowManager windowManager)
{
this.windowManager = windowManager;
}
public string DisplayName
{
get { return "Main Window"; }
set { }
}
public bool AlwaysOnTop
{
get { return Settings.Default.DropWindowAlwaysOnTop; }
set
{
Settings.Default.DropWindowAlwaysOnTop = value;
Settings.Default.Save();
NotifyOfPropertyChange(() => AlwaysOnTop);
//todo: toggle the AOT attribute of the window
}
}
public void FileDropped(DragEventArgs eventArgs)
{
if (eventArgs.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] droppedFilePaths = eventArgs.Data.GetData(DataFormats.FileDrop, true) as string[];
foreach (string path in droppedFilePaths)
{
MessageBox.Show(path);
}
windowManager.ShowWindow(new WizardViewModel());
}
}
}
}
You can use the settings parameter of the ShowWindow method to set any property (e.g. Topmost) on the created window with a dictionary containing propertyname-value pairs:
windowManager.ShowWindow(new WizardViewModel(),
settings: new Dictionary<string,object> { {"Topmost", AlwaysOnTop} });
If you want to change the Topmost property of the already created window I see three options (in the order of preference):
Create an AlwaysOnTop property on the WizardViewModel and store the viewmodel in a private field and delegate the AlwaysOnTop to the WizardViewModel:
private WizardViewModel wizardViewModel;
public void FileDropped(DragEventArgs eventArgs)
{
//...
wizardViewModel = new WizardViewModel()
windowManager.ShowWindow(wizardViewModel);
}
public bool AlwaysOnTop
{
get { return Settings.Default.DropWindowAlwaysOnTop; }
set
{
//...
if (wizardViewModel != null)
wizardViewModel.AlwaysOnTop = value;
}
}
And in your view you can bind the WizardViewModel's AlwaysOnTop property to the window's TopMost property.
You can use the Application.Windows to retrieve the window. E.g. set the Name property of the created Window with the settings dictionary and then:
windowManager.ShowWindow(new WizardViewModel(),
settings: new Dictionary<string,object>
{ {"Topmost", AlwaysOnTop}, {"Name", "WizardWindow"} });
public bool AlwaysOnTop
{
get { return Settings.Default.DropWindowAlwaysOnTop; }
set
{
//...
var wizardViewModel = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(w => w.Name == "WizardWindow");
if (wizardViewModel != null)
wizardViewModel.AlwaysOnTop = value;
}
}
Derive from the WindowManager and register it in your Bootstrapper and then you can override the CreateWindow, EnsureWindow etc. methods to store the created windows somewhere set the additional properties etc.

How can i use engine object in my console application

"How can i use engine in my console application"
I shouldn't use the ITemplate-interface and Transform-Method.
I am using Tridion 2011
Could anyone please suggest me.
You can't. The Engine class is part of the TOM.NET and that API is explicitly reserved for use in:
Template Building Blocks
Event Handlers
For all other cases (such as console applications) you should use the Core Service.
There are many good questions (and articles on other web sites) already:
https://stackoverflow.com/search?q=%5Btridion%5D+core+service
http://www.google.com/#q=tridion+core+service
If you get stuck along the way, show us the relevant code+configuration you have and what error message your get (or at what step you are stuck) and we'll try to help from there.
From a console application you should use the Core Service. I wrote a small example using the Core Service to search for items in the content manager.
Console.WriteLine("FullTextQuery:");
var fullTextQuery = Console.ReadLine();
if (String.IsNullOrWhiteSpace(fullTextQuery) || fullTextQuery.Equals(":q", StringComparison.OrdinalIgnoreCase))
{
break;
}
Console.WriteLine("SearchIn IdRef:");
var searchInIdRef = Console.ReadLine();
var queryData = new SearchQueryData
{
FullTextQuery = fullTextQuery,
SearchIn = new LinkToIdentifiableObjectData
{
IdRef = searchInIdRef
}
};
var results = coreServiceClient.GetSearchResults(queryData);
results.ToList().ForEach(result => Console.WriteLine("{0} ({1})", result.Title, result.Id));
Add a reference to Tridion.ContentManager.CoreService.Client to your Visual Studio Project.
Code of the Core Service Client Provider:
public interface ICoreServiceProvider
{
CoreServiceClient GetCoreServiceClient();
}
public class CoreServiceDefaultProvider : ICoreServiceProvider
{
private CoreServiceClient _client;
public CoreServiceClient GetCoreServiceClient()
{
return _client ?? (_client = new CoreServiceClient());
}
}
And the client itself:
public class CoreServiceClient : IDisposable
{
public SessionAwareCoreServiceClient ProxyClient;
private const string DefaultEndpointName = "netTcp_2011";
public CoreServiceClient(string endPointName)
{
if(string.IsNullOrWhiteSpace(endPointName))
{
throw new ArgumentNullException("endPointName", "EndPointName is not specified.");
}
ProxyClient = new SessionAwareCoreServiceClient(endPointName);
}
public CoreServiceClient() : this(DefaultEndpointName) { }
public string GetApiVersionNumber()
{
return ProxyClient.GetApiVersion();
}
public IdentifiableObjectData[] GetSearchResults(SearchQueryData filter)
{
return ProxyClient.GetSearchResults(filter);
}
public IdentifiableObjectData Read(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
public ApplicationData ReadApplicationData(string subjectId, string applicationId)
{
return ProxyClient.ReadApplicationData(subjectId, applicationId);
}
public void Dispose()
{
if (ProxyClient.State == CommunicationState.Faulted)
{
ProxyClient.Abort();
}
else
{
ProxyClient.Close();
}
}
}
When you want to perform CRUD actions through the core service you can implement the following methods in the client:
public IdentifiableObjectData CreateItem(IdentifiableObjectData data)
{
data = ProxyClient.Create(data, new ReadOptions());
return data;
}
public IdentifiableObjectData UpdateItem(IdentifiableObjectData data)
{
data = ProxyClient.Update(data, new ReadOptions());
return data;
}
public IdentifiableObjectData ReadItem(string id)
{
return ProxyClient.Read(id, new ReadOptions());
}
To construct a data object of e.g. a Component you can implement a Component Builder class that implements a create method that does this for you:
public ComponentData Create(string folderUri, string title, string content)
{
var data = new ComponentData()
{
Id = "tcm:0-0-0",
Title = title,
Content = content,
LocationInfo = new LocationInfo()
};
data.LocationInfo.OrganizationalItem = new LinkToOrganizationalItemData
{
IdRef = folderUri
};
using (CoreServiceClient client = provider.GetCoreServiceClient())
{
data = (ComponentData)client.CreateItem(data);
}
return data;
}
Hope this gets you started.

Resources