How to reduce my redundant code, creating generic methods? - c#

I have a code to insert and update entities, but the logic are very similar: instance a controller, validate de request, if error, resturns Failed, else execute the operation.
/// <summary>
/// Method Add with similar code in Update method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Add(PersonInsertRequest item)
{
var result = new PersonResponse();
var controller = new PersonController(classmates);
result.Messages = controller.ValidateInsert(item);
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = controller.ExecuteInsert(item);
}
return result;
}
/// <summary>
/// Method Update with similar code in Add method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Update(PersonUpdateRequest item)
{
var result = new PersonResponse();
var controller = new PersonController(classmates);
result.Messages = controller.ValidateUpdate(item);
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = controller.ExecuteUpdate(item);
}
return result;
}
-
I have tried to use delegates, but I can't use them, because I cannot assign a delegate to controller.ValidateInsert(item);
public class BaseLogic
{
public delegate List<Message> Validator(BaseRequest request);
public delegate BaseResponse Executor(BaseRequest request);
public BaseResponse Execute(BaseRequest request, Validator funcValidator, Executor funcExecutor)
{
var result = new BaseResponse();
result.Messages = funcValidator(request);
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = funcExecutor(request);
}
return result;
}
}
I want to reduce Add method and Update method in another more generic.

using System;
using System.Collections.Generic;
using System.Linq;
class Test
{
private object classmates;
public PersonResponse Add(PersonInsertRequest item)
{
var controller = new PersonController(classmates);
return ValidateAndExecute(() => controller.ValidateInsert(item),
() => controller.ExecuteInsert(item));
}
public PersonResponse Update(PersonUpdateRequest item)
{
var controller = new PersonController(classmates);
return ValidateAndExecute(() => controller.ValidateUpdate(item),
() => controller.ExecuteUpdate(item));
}
private PersonResponse ValidateAndExecute(Func<IEnumerable<string>> validator,
Func<PersonResponse> execute)
{
var result = new PersonResponse();
result.Messages = validator();
if (result.Messages != null && result.Messages.Any())
{
result.Status = "failed";
}
else
{
result = execute();
}
return result;
}
}

With my generic method in my base class, I can refactorize my methods
/// <summary>
/// Method Add with similar code in Update method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Add(PersonInsertRequest item)
{
var controller = new PersonController(classmates);
Validator myValidator = request => controller.ValidateInsert((PersonInsertRequest)request);
Executor myExecutor = request => controller.ExecuteInsert((PersonInsertRequest)request);
var result = Execute(item, myValidator, myExecutor);
return result as PersonResponse;
}
/// <summary>
/// Method Update with similar code in Add method
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public PersonResponse Update(PersonUpdateRequest item)
{
var controller = new PersonController(classmates);
Validator myValidator = request => controller.ValidateUpdate((PersonUpdateRequest)request);
Executor myExecutor = request => controller.ExecuteUpdate((PersonUpdateRequest)request);
var result = Execute(item, myValidator, myExecutor);
return result as PersonResponse;
}

Related

Cosmos DB - CreateCollectionIfNotExistsAsync Generic method

I am using cosmos DB and I have created below generic repository for CRUD operations.
public class CosmosDBRepository : ICosmosDBRepository
{
private readonly DocumentClient _client;
private readonly string DatabaseId = "FleetHub";
public CosmosDBRepository()
{
var endpoint = CloudConfigurationManager.GetSetting("CosmoDbEndpoint");
var authkey = CloudConfigurationManager.GetSetting("CosmoDbAuthKey");
try
{
if (endpoint == null || authkey == null)
{
throw new ArgumentNullException("CosmoDbEndpoint or CosmoDbAuthKey could not be found in the config file, check your settings.");
}
if (_client == null)
{
_client = new DocumentClient(new Uri(endpoint), authkey, connectionPolicy: new ConnectionPolicy { EnableEndpointDiscovery = false });
}
CreateDatabaseIfNotExistsAsync().Wait();
CreateCollectionIfNotExistsAsync().Wait();
}
catch (Exception e)
{
throw new Exception($"Initialise failed CosmoDbEndpoint {endpoint} or CosmoDbAuthKey {authkey} could not be found in the config file, check your settings. {e.Message}");
}
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="partitionkey"></param>
/// <returns></returns>
public async Task<T> GetItemAsync<T>(string id, string partitionkey) where T : class
{
try
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
Document document = await _client.ReadDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), new RequestOptions { PartitionKey = new PartitionKey(partitionkey) });
return (T)(dynamic)document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
else
{
throw;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public async Task<Document> CreateItemAsync<T>(T item) where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
return await _client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), item);
}
public async Task<IEnumerable<T>> GetItemsAsync<T>(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByDesc, int takeCount = -1)
where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
var criteria = _client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), new FeedOptions { EnableCrossPartitionQuery = true })
.Where(predicate)
.OrderByDescending(orderByDesc)
.AsDocumentQuery();
IDocumentQuery<T> query = criteria;
List<T> results = new List<T>();
while (query.HasMoreResults)
{
if (takeCount > -1 && results.Count >= takeCount)
{
break;
}
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="item"></param>
/// <returns></returns>
public async Task<Document> UpdateItemAsync<T>(string id, T item) where T : class
{
string CollectionId = GetAttributeCosmoDbCollection<T>(typeof(T));
return await _client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(DatabaseId, CollectionId, id), item);
}
#region private methods
private async Task CreateDatabaseIfNotExistsAsync()
{
try
{
await _client.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(DatabaseId));
}
catch (DocumentClientException e)
{
if (e.StatusCode == System.Net.HttpStatusCode.NotFound)
{
await _client.CreateDatabaseAsync(new Database { Id = DatabaseId });
}
else
{
throw;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private string GetPartitionKeyAttributeCosmoDbCollection(Type t)
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.PartitionKey;
}
private string GetAttributeCosmoDbCollection<T>(Type t) where T : class
{
// Get instance of the attribute.
CosmoDBCollection attribute =
(CosmoDBCollection)Attribute.GetCustomAttribute(t, typeof(CosmoDBCollection));
if (attribute == null)
{
throw new Exception("The attribute CosmoDbCollection was not found.");
}
return attribute.Name;
}
#endregion
}
Here is CosmoDBCollection class:
public class CosmoDBCollection : Attribute
{
public string Name { get; set; }
public string PartitionKey { get; set; }
}
I am calling CreateCollectionIfNotExistsAsync().Wait(); in the constructor and this method required collectionId. How Can I pass CollectionId to this method? As this is the generic repository.
Do I need to create a Generic CreateCollectionIfNotExistsAsync() method?
If your collection name is based off <T>, why not simply have CosmosDBRepository<T> as the actual class. That way you can get the value also on the constructor.
Ideally it would also be a readonly private property that you only calculate once (on the constructor) and reuse on all operations to avoid paying the cost to construct it later on (since it doesn't change).

SQLite Implementation in VS 2019

I'm still really new to coding and trying to make my first WPF application. I have been trying to implement sqlite for the past like 3 days now.
I am using VS 2019. I have downloaded the SQLite Toolbox and am following the instructions here - https://github.com/ErikEJ/SqlCeToolbox/wiki/EF6-workflow-with-SQLite-DDEX-provider. I did a full installation. Was I supposed to install it in my project directory? Because now I just have a bunch of files and nothing seems to have changed in Studio. I tried using Install.exe, but it returned a "confirm option not enabled" error. Looking at a similar question, I tried putting the files in an external folder in my project, and then installed the System.Data.SQLite.EF6.dll to my GAC using the VS Dev Console. The toolbox doesn't see any changes, and does not recognize the dll and I'm having a hard time finding reliable information for my version. Thanks for any help getting pointed in the right direction!
I'm not sure why you mention toolbox as far as I'm aware you access the SQLite functionality programmatically.
The NuGet packages that I recently used for a Xamarin project (SQLite-net-pcl by Frank Krueger and supporting libraries) allowed me to use pretty simple object mapping without recourse to SQL like strings.
I use a lot of interfaces in my code, but here's my all access database class
:
public class AllAccessDataTableBaseSqLite<T> : IDataAccessRead<T>, IDataAccessWrite<T>,IDataAccessExpressionSearch<T>, IDataAccessDelete<T> where T: IDataRecord, new()
{
//Note that this static value will only apply to those classes based on the same generic type e.g. all DataTableBase<User> instances etc.
public static SQLiteAsyncConnection DBConnection;
/// <summary>
/// Lock object to prevent multi-thread interruption of code segment.
/// </summary>
public static readonly object CollisionLock = new object();
/// <summary>
/// Constructor
/// </summary>
public AllAccessDataTableBaseSqLite()
{
lock (CollisionLock)
{
if (DBConnection != null)
{
DBConnection.CreateTableAsync<T>().Wait();
return;
}
try
{
string directory;
if (DeviceInfo.Platform != DevicePlatform.Unknown)
{
directory = FileSystem.AppDataDirectory;
}
else
{
directory = "DataStore";
var directoryInfo = Directory.CreateDirectory(directory);
directory = directoryInfo.FullName;
}
var path = Path.Combine(directory, $"{typeof(T).Name}.db");
if (!File.Exists(path))
{
using var fileStream = File.Create(path);
fileStream.Close();
}
DBConnection = new SQLiteAsyncConnection(path);
DBConnection.CreateTableAsync<T>().Wait();
}
catch (Exception ex)
{
if (ex is UnauthorizedAccessException)
{
}
}
}
}
/// <summary>
/// Create the data table
/// </summary>
/// <returns></returns>
public async Task<CreateTableResult> CreateTableAsync()
{
if (DBConnection != null)
{
return await DBConnection.CreateTableAsync<T>();
}
return CreateTableResult.Migrated;
}
/// <summary>
/// Create a new record entry
/// </summary>
/// <param name="entity">Data entity to enter</param>
/// <param name="user">Current User information</param>
/// <returns>New entry record if successful</returns>
public async Task<T> CreateAsync(T entity, IUserRecord user)
{
if (entity == null)
{
return default(T);
}
if (DBConnection == null)
{
return default(T);
}
entity.CreatedDate = DateTime.UtcNow;
entity.CreatedByUserId = user.Id;
entity.Id = 0;
try
{
await DBConnection.InsertAsync(entity);
}
catch (SQLiteException e)
{
if (e.Message == "Constraint")
{
throw new InvalidConstraintException(e.Message, e.InnerException);
}
}
var result = entity;
return result;
}
/// <summary>
/// Update a collection of new entities of type T to the data table.
/// All entities should be present within the data table
/// </summary>
/// <param name="entityList">Entity collection</param>
/// <param name="user">user making the change</param>
/// <returns>ID of entities successfully updated or added</returns>
public async Task<int> UpdateAllAsync(IEnumerable<T> entityList, IUserRecord user)
{
var result = 0;
foreach (var t in entityList)
{
if (null != await UpdateAsync(t, user))
{
result++ ;
}
}
return result;
}
/// <summary>
/// Obtain the data record with the given Id
/// </summary>
/// <param name="id">Id value to select the record by</param>
/// <returns>A valid record if found otherwise null</returns>
public async Task<T> GetById(int id)
{
if (DBConnection == null)
{
return default(T);
}
return await DBConnection.Table<T>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
/// <summary>
/// This function returns all database entries that are not marked deleted or changed
/// Warning: The data set may be very large
/// </summary>
/// <returns>A list of entries</returns>
public async Task<List<T>> GetAll()
{
if (DBConnection != null)
{
return await DBConnection.Table<T>().Where(x=>x.ChangedDate==default && x.DeletedDate==default)
.ToListAsync();
}
return new List<T>();
}
/// <inheritdoc />
public async Task<List<T>> GetAllHistoric() => await DBConnection.Table<T>().ToListAsync();
/// <summary>
/// This function is used to update the supplied record entry within the database.
/// If the supplied record does not have a non-zero value Id field it is assumed to be a
/// new record to be inserted into the database.
/// </summary>
/// <param name="entity">Record to update</param>
/// <param name="user">User performing the action</param>
/// <returns></returns>
public async Task<T> UpdateAsync(T entity, IUserRecord user)
{
if (DBConnection == null)
{
return default(T);
}
if (entity == null)
{
return default(T);
}
var newRecord = (T) ((entity) as BaseRecord<T>)?.Clone();
if (null == newRecord)
{
return default(T);
}
//if Id is zero assume that the record is new and to be added
if (newRecord.Id == 0)
{
if (user != null)
{
newRecord.CreatedByUserId = user.Id;
}
newRecord.CreatedDate = DateTime.UtcNow;
newRecord.Id = await DBConnection.InsertAsync(newRecord);
return newRecord;
}
// Id is not zero and thus a new record should be created linked to the old record.
var oldRecord = await GetById(newRecord.Id);
oldRecord.ChangedDate = DateTime.UtcNow;
if (user != null)
{
oldRecord.ChangedByUserId = user.Id;
}
try
{
var result = await DBConnection.UpdateAsync(oldRecord);
}
catch (Exception e)
{
Debug.WriteLine($"UpdateAsync {e.Message}");
}
newRecord.PreviousRecordId = oldRecord.Id;
newRecord.Id = 0;
return await CreateAsync(newRecord, user);
}
/// <inheritdoc />
public async Task<int> DeleteAsync(T entity)
{
if (DBConnection == null)
{
return -1;
}
return await DBConnection.DeleteAsync(entity);
}
/// <inheritdoc />
public async Task DeleteAll()
{
await DBConnection.DropTableAsync<T>();
await CreateTableAsync();
}
/// <inheritdoc />
public async Task<PagedResult<T>> GetAllPagedResult(int recordId, uint maxResults = 100)
{
if (DBConnection == null)
{
return null;
}
List<T> list;
if (maxResults == 0)
{
list = await GetAll();
}
else
{
list = await DBConnection.Table<T>().Where(x => (x.Id >= recordId && x.ChangedDate == default && x.DeletedDate == default)).ToListAsync();
if (list.Count() > maxResults)
{
list = list.GetRange(0, (int) maxResults);
}
}
return new PagedResult<T>(list, list.Count());
}
/// <inheritdoc />
public async Task<IEnumerable<T>> FindAsyncOrdered<TValue>(Expression<Func<T, bool>> predicate = null,
Expression<Func<T, TValue>> orderBy = null)
{
var query = DBConnection.Table<T>();
if (predicate != null)
{
query = query.Where(predicate);
}
if (orderBy != null)
{
query = query.OrderBy<TValue>(orderBy);
}
return await query.ToListAsync();
}
/// <inheritdoc />
public async Task<T> FindFirst(Expression<Func<T, bool>> predicate) => await DBConnection.FindAsync(predicate);
}
I'm using data classes based upon:
public interface IDataRecord
{
/// <summary>
/// Identifier for record
/// </summary>
int Id { get; set; }
/// <summary>
/// Link to previous version of record
/// </summary>
int PreviousRecordId { get; set; }
/// <summary>
/// User Identity that made the change
/// </summary>
int ChangedByUserId { get; set; }
/// <summary>
/// Date when the data record was last changed
/// </summary>
DateTime ChangedDate { get; set; }
/// <summary>
/// Identity of User that deleted the record
/// </summary>
int DeletedByUserId { get; set; }
/// <summary>
/// Date when the data record was deleted
/// </summary>
DateTime DeletedDate { get; set; }
/// <summary>
/// Identity of User that created the record
/// </summary>
int CreatedByUserId { get; set; }
/// <summary>
/// Date when the data record was added
/// </summary>
DateTime CreatedDate { get; set; }
object Clone();
}
Obviously you don't have to use this, but put simply for my application implementation each type of data record is stored in its own data file (thus 1 table per file) and this is created at the beginning in the constructor.
The SQLite db connection is created using the data file path.
Table is created using the dbconnection
edit
I've had a closer look at your code.
Points to note are:
You don't appear to be creating a table.
Access to non-app folders is restricted if you chose to create a UWP rather than base WPF project - be aware of folder access permissions when running apps especially in release mode.

Singleton dictionary is not being singleton

I have a dictionary in a singleton class. I am saving there the pair , every time I access to that dictionary from the method that is creating the token it shows all the credentials that I've stored there.
But when I access from another class in another project of the solutions it displays the dictionary empty. Can anybody tell me why this happens?
This is the class that manage the dictionary:
public class UserAccessToken
{
public Dictionary<string, string> UserDictionary { get; set; }
private static UserAccessToken _instance;
private UserAccessToken() { }
public static UserAccessToken Instance
{
get
{
if (_instance == null)
_instance = new UserAccessToken
{
UserDictionary = new Dictionary<string, string>()
};
return _instance;
}
}
}
This is the method that insert the key,value pair in the dictionary:
public override Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
{
var accessToken = context.AccessToken;
if (context.Properties.Dictionary.ContainsKey("userName"))
{
var username = context.Properties.Dictionary["userName"];
// If I access here multiple times the singleton works
UserAccessToken.Instance.UserDictionary[username] = accessToken;
}
return Task.FromResult<object>(null);
}
This is the method where I access the dictionary, from here I can see that it's empty:
private bool IsTokenValid(HttpContextBase httpContext)
{
var username = httpContext.User.Identity.Name;
var userTokens = UserAccessToken.Instance.UserDictionary;
var tokenToAccess = httpContext.Request.Headers["Authorization"];
tokenToAccess = tokenToAccess.Replace("Bearer ", "");
if (userTokens.ContainsKey(username))
{
var token = userTokens[username];
if (token == tokenToAccess) return true;
}
return true;
}
I already solved my problem, but I'll let my solution here in case could be useful for somebody.
The problem is that if you are running two different projects, that will mean two different process, so, what I wanted to do is pretty impossible. I used Redis for this and it is working well.
This is an example of Redis use:
public class CallManagerCache : ICallManagerMethods{
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer
.Connect(CloudConfigurationManager.GetSetting("RedisConnectionString")));
public static ConnectionMultiplexer cacheConnection
{
get
{
return lazyConnection.Value;
}
}
/// <summary>
/// Here you save the value in cache, you get the connection, then StringSetAsync is in charge of saving the value
/// </summary>
/// <param name="name"></param>
/// <param name="template"></param>
public async Task UpdateCallInstance(int id, byte[] data, bool instanceForCallback = false, TimeSpan? timespan = null)
{
var cache = cacheConnection.GetDatabase();
await cache.StringSetAsync(instanceForCallback ? $"Call_{id}" : id.ToString(), data, timespan ?? new TimeSpan(0, 0, 15, 0));
}
/// <summary>
/// Here you get the value in cache, you get the connection, then StringGetAsync is in charge of getting the value
/// </summary>
/// <param name="name"></param>
/// <param name="template"></param>
public async Task<CallInstance> GetById(int id, bool isForCallback)
{
var cache = cacheConnection.GetDatabase();
var callInstance = new CallInstance
{
Id = id,
InstanceData = await cache.StringGetAsync(isForCallback ? $"Call_{id}" : id.ToString())
};
return callInstance;
}
}

Install services in assembly with specific namespace in a console app with castle windsor

I have the following setup: A console application, and a services project with a range of services.
I am trying to use Windsor Castle to install specific services in the application, depending on their namespace in the application.
I have got the following to work fine in my application:
Container.Install(Castle.Windsor.Installer.Configuration.FromXmlFile("components.config"));
However, I have trouble getting the "register all service with specific namespace to work".
In a web application I have made previously, I got the following code to work. However, it seems that when I use Container.Register in my console application, I cannot resolve the services later on.
Code I've previously used in a web application:
// All services in service DLL
var assembly = Assembly.LoadFrom(Server.MapPath("~/bin/LetterAmazer.Business.Services.dll"));
;
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.FulfillmentJobs")
.WithServiceAllInterfaces());
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Services.PaymentMethods.Implementations")
.WithServiceAllInterfaces());
// All factories in service DLL
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("LetterAmazer.Business.Services.Factory")
.WithServiceAllInterfaces());
Container.Register(Component.For<LetterAmazerEntities>());
When I use the Container.Register code in my console application, I cannot do the following:
orderService = ServiceFactory.Get<IOrderService>();
fulfillmentService = ServiceFactory.Get<IFulfillmentService>();
As I get a "service could not be resolved".
The code is run in a BackgroundService class, with the following code:
public void Start()
{
logger.Info("Starting Background Service...");
Container.Install(Castle.Windsor.Installer.Configuration.FromXmlFile("components.config"));
ISchedulerFactory scheduleFactory = new StdSchedulerFactory();
scheduler = scheduleFactory.GetScheduler();
scheduler.Start();
ThreadStart threadStart = new System.Threading.ThreadStart(ScheduleJobs);
new Thread(threadStart).Start();
logger.Info("DONE!");
}
So to sum it all up: how do register all services / classes with a specific namespace, in an external DLL, in a console application?
EDIT:
ServiceFactory.cs:
public class ServiceFactory
{
private static ServiceFactory instance = new ServiceFactory();
private IWindsorContainer container = new WindsorContainer();
private ServiceFactory()
{
}
/// <summary>
/// Gets the container.
/// </summary>
/// <value>The container.</value>
public static IWindsorContainer Container
{
get { return instance.container; }
}
/// <summary>
/// Gets this instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Get<T>()
{
return instance.container.Resolve<T>();
}
/// <summary>
/// Gets all this instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IList<T> GetAll<T>()
{
return instance.container.ResolveAll<T>();
}
/// <summary>
/// Gets the specified name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name">The name.</param>
/// <returns></returns>
public static T Get<T>(string name)
{
return (T)instance.container.Resolve<T>(name);
}
/// <summary>
/// Gets all the specified name.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="name">The name.</param>
/// <returns></returns>
public static IList<T> GetAll<T>(string name)
{
return instance.container.ResolveAll<T>(name);
}
}
EDIT-2
If I try to make a resolve in the BackgroundService, after registering the services to my container, I get a:
An unhandled exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll
Additional information: No component for supporting the service LetterAmazer.Business.Services.Domain.Orders.IOrderService was found
However, I can see that in debug, the IOrderService exists in the "All services" in my container.
EDIT-3
public interface IOrderService
{
Order Create(Order order);
Order Update(Order order);
void UpdateByLetters(IEnumerable<Letter> letters);
List<Order> GetOrderBySpecification(OrderSpecification specification);
Order GetOrderById(int orderId);
Order GetOrderById(Guid orderId);
void Delete(Order order);
List<OrderLine> GetOrderLinesBySpecification(OrderLineSpecification specification);
void ReplenishOrderLines(Order order);
}
EDIT-4: Order service
Note: some of the implementation has been cut
public class OrderService : IOrderService
{
private IOrderFactory orderFactory;
private LetterAmazerEntities repository;
private ILetterService letterService;
private ICustomerService customerService;
public OrderService(LetterAmazerEntities repository,
ILetterService letterService,
IOrderFactory orderFactory, ICustomerService customerService)
{
this.repository = repository;
this.letterService = letterService;
this.orderFactory = orderFactory;
this.customerService = customerService;
}
public Order Create(Order order)
{
DbOrders dborder = new DbOrders();
foreach (var orderLine in order.OrderLines)
{
var dbOrderLine = setOrderline(orderLine);
dborder.DbOrderlines.Add(dbOrderLine);
}
dborder.Guid = Guid.NewGuid();
dborder.OrderCode = GenerateOrderCode();
dborder.OrderStatus = (int)OrderStatus.Created;
dborder.DateCreated = DateTime.Now;
dborder.DateUpdated = DateTime.Now;
dborder.PaymentMethod = "";
dborder.CustomerId = order.Customer != null ? order.Customer.Id : 0;
Price price = new Price();
price.PriceExVat = order.CostFromLines();
price.VatPercentage = order.Customer.VatPercentage();
order.Price = price;
dborder.Total = order.Price.Total;
dborder.VatPercentage = order.Price.VatPercentage;
dborder.PriceExVat = order.Price.PriceExVat;
repository.DbOrders.Add(dborder);
repository.SaveChanges();
return GetOrderById(dborder.Id);
}
public Order GetOrderById(Guid orderId)
{
DbOrders dborder = repository.DbOrders.FirstOrDefault(c => c.Guid == orderId);
if (dborder == null)
{
throw new ItemNotFoundException("Order");
}
var lines = repository.DbOrderlines.Where(c => c.OrderId == dborder.Id).ToList();
var order = orderFactory.Create(dborder, lines);
return order;
}
public Order GetOrderById(int orderId)
{
DbOrders dborder = repository.DbOrders.FirstOrDefault(c => c.Id == orderId);
if (dborder == null)
{
throw new ItemNotFoundException("Order");
}
var lines = repository.DbOrderlines.Where(c => c.OrderId == orderId).ToList();
var order = orderFactory.Create(dborder, lines);
return order;
}
public void Delete(Order order)
{
var dborder = repository.DbOrders.FirstOrDefault(c => c.Id == order.Id);
repository.DbOrders.Remove(dborder);
repository.SaveChanges();
}
public void DeleteOrder(Order order)
{
var dborder = repository.DbOrders.FirstOrDefault(c => c.Id == order.Id);
repository.DbOrders.Remove(dborder);
repository.SaveChanges();
}
#endregion
}
I think you can do the same thing in a console application too. You just have to create the assembly instance. Considering that the assembly is in the same folder, this should work:
Assembly assembly = Assembly.LoadFrom("MyAssembly.dll");
Container.Register(
Classes.FromAssembly(assembly)
.InNamespace("MyNamespace")
.WithServiceAllInterfaces());

Comparing a List<T> with another List<t>

I have been reading on how to compare a list with one annother. I have tried to implement the IEquatable interface. Here is what i have done so far:
/// <summary>
/// A object holder that contains a service and its current failcount
/// </summary>
public class ServiceHolder : IEquatable<ServiceHolder>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="service"></param>
public ServiceHolder(Service service)
{
Service = service;
CurrentFailCount = 0;
}
public Service Service { get; set; }
public UInt16 CurrentFailCount { get; set; }
/// <summary>
/// Public equal method
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ServiceHolder tmp = obj as ServiceHolder;
if (tmp == null)
{
return false;
}
else
{
return Equals(tmp);
}
}
/// <summary>
/// Checks the internal components compared to one annother
/// </summary>
/// <param name="serviceHolder"></param>
/// <returns>tru eif they are the same else false</returns>
public bool Equals(ServiceHolder serviceHolder)
{
if (serviceHolder == null)
{
return false;
}
if (this.Service.Id == serviceHolder.Service.Id)
{
if (this.Service.IpAddress == serviceHolder.Service.IpAddress)
{
if (this.Service.Port == serviceHolder.Service.Port)
{
if (this.Service.PollInterval == serviceHolder.Service.PollInterval)
{
if (this.Service.ServiceType == serviceHolder.Service.ServiceType)
{
if (this.Service.Location == serviceHolder.Service.Location)
{
if (this.Service.Name == this.Service.Name)
{
return true;
}
}
}
}
}
}
}
return false;
}
}
and this is where I use it:
private void CheckIfServicesHaveChangedEvent()
{
IList<ServiceHolder> tmp;
using (var db = new EFServiceRepository())
{
tmp = GetServiceHolders(db.GetAll());
}
if (tmp.Equals(Services))
{
StateChanged = true;
}
else
{
StateChanged = false;
}
}
Now when I debug and I put a break point in the equals function it never gets hit.
This leads me to think I have implemented it incorrectly or Im not calling it correctly?
If you want to compare the contents of two lists then the best method is SequenceEqual.
if (tmp.SequenceEquals(Services))
This will compare the contents of both lists using equality semantics on the values in the list. In this case the element type is ServiceHolder and as you've already defined equality semantics for this type it should work just fine
EDIT
OP commented that order of the collections shouldn't matter. For that scenario you can do the following
if (!tmp.Except(Services).Any())
You can compare lists without the order most easily with linq.
List<ServiceHolder> result = tmp.Except(Services).ToList();

Categories