Unity IOC and Factory pattern, and repository pattern - c#

I am trying to use the Unity Block of the enterprise library in a program i am writing.
But i think i am using dependency injection wrong. I was wondering if some one could point me in the right direction.
static void Main(string[] args)
{
using (IUnityContainer container = new UnityContainer())
{
InitialiseContainer(container);
DataCopierFactory dcFactory = new DataCopierFactory();
ERunOptions dataCopierType = ExtractParams(args);
IDataCopier dataCopier = dcFactory.CreateDataCopier((int)dataCopierType, container);
dataCopier.DetectChanges();
dataCopier.ParseData();
dataCopier.CopyData();
}
}
}
//use the ioc container to register the EF context type to the repository interfaces..
private static void InitialiseContainer(IUnityContainer container)
{
//add Extensions:
container.AddNewExtension<Interception>();
//Licence Schedule
container.RegisterType<IEFContext, LTE_DownFromWeb_EFContext>("DataCopier.ScheduleDataCopier.Source");
container.RegisterType<IEFContext, LTE_Licensing_EFContext>("DataCopier.ScheduleDataCopier.Destination");
container.RegisterType<IRepositorySession>("Schedule_Source",new InjectionConstructor(container.Resolve<IEFContext>("DataCopier.ScheduleDataCopier.Source")));
container.RegisterType<IRepositorySession>("Schedule_Destination",new InjectionConstructor(container.Resolve<IEFContext>("DataCopier.ScheduleDataCopier.Destination")));
}
So basically the DataCopier Factory creates an instance of a DataCopier like so:
DataCopierFactory:
//return a data copier that will transfer data from any DB to any other DB
public IDataCopier CreateDataCopier(int i, IUnityContainer container)
{
switch(i)
{
case 1:
return new ScheduleDataCopier(container);
default:
throw new InvalidOperationException("Parameter " + i + " does not exist");
}
}
a data copier looks like this:
class ScheduleDataCopier : IDataCopier
{
private List<Site> _sites;
private List<SitesAndApparatuses> _scheduleList;
private IUnityContainer _container;
public ScheduleDataCopier(IUnityContainer container)
{
_container = container;
_scheduleList = new List<SitesAndApparatuses>();
}
//check if new sites registration has arrived in tblSites on down from web db.
public bool DetectChanges()
{
using (var db = _container.Resolve<IRepositorySession>("Schedule_Source"))
{
SiteAudit lastSite = new SitesAuditRepository().GetLatest();
var sitesRepo = new SitesRepository();
var sites = sitesRepo.Where(x => x.SID > lastSite.SALatestSID);
if (sites.Count() < 1)
{
return false;
}
_sites = sites.ToList();
db.Dispose();
}
return true;
}
//parse the data into a list of object SitesAndApparatuses
public bool ParseData()
{
try
{
foreach (Site s in _sites)
{
var schedule = (SitesAndApparatuses)XmlObjectBuilder.Deserialize(typeof(SitesAndApparatuses), s.XMLFile);
schedule.acCode = s.Registration.RAcCode;
_scheduleList.Add(schedule);
}
}
catch (Exception ex)
{
throw new NotImplementedException("HANDLE THIS SHIT!", ex);
}
return true;
}
public bool CopyData()
{
try
{
using (var db = _container.Resolve<IRepositorySession>("Schedule_Destination"))
{
var licensingScheduleRepo = new LicensingScheduleRepository();
//some logic
db.Commit();
}
}
catch (Exception ex)
{
}
return true;
}
}
Second question, i resolve my unit of work object called RepositorySession in the Datacopier classes using the unity container i passed... is this the wrong approach and why, im struggling to find any info on it online?
This is probably too much code for someone to read.. but im hoping for an answer!
Thanks in advance
Neil

I'd do something like:
container.RegisterType<IEFContext, LTE_DownFromWeb_EFContext>("Source");
container.RegisterType<IEFContext, LTE_Licensing_EFContext>("Destination");
container.RegisterType<IRepositorySession>("Source",new InjectionConstructor(new ResolvedParameter<IEFContext>("Source"));
container.RegisterType<IRepositorySession>("Destination",new InjectionConstructor(new ResolvedParameter<IEFContext>("Destination")));
container.RegisterType<IDataCopier,ScheduleDataCopier>("0",new InjectionConstructor(new[] {new ResolvedParameter<IRepositorySession("Source"),new ResolvedParameter<IRepositorySesison>("Destination")}));
//Now resolve
ERunOptions dataCopierType = ExtractParams(args);
IDataCopier dataCopier = container.Resolve<IDataCopier(dataCopierType.ToString());
dataCopier.DetectChanges();
dataCopier.ParseData();
dataCopier.CopyData();
DataCopier Class
class ScheduleDataCopier : IDataCopier
{
private List<Site> _sites;
private List<SitesAndApparatuses> _scheduleList;
private IRepositorySession _source;
private (IRepositorySession _destination;
public ScheduleDataCopier(IRepositorySession source, (IRepositorySession destination)
{
_source=source;
_destination=destination;
_scheduleList = new List<SitesAndApparatuses>();
}
//check if new sites registration has arrived in tblSites on down from web db.
public bool DetectChanges()
{
SiteAudit lastSite = new SitesAuditRepository().GetLatest();
var sitesRepo = new SitesRepository();
var sites = sitesRepo.Where(x => x.SID > lastSite.SALatestSID);
if (sites.Count() < 1)
{
return false;
}
_sites = sites.ToList();
_source.DoSomething();
_source.CommitAndReleaseResources();//clean up but leave object reusable
return true;
}
//parse the data into a list of object SitesAndApparatuses
public bool ParseData()
{
try
{
foreach (Site s in _sites)
{
var schedule = (SitesAndApparatuses)XmlObjectBuilder.Deserialize(typeof(SitesAndApparatuses), s.XMLFile);
schedule.acCode = s.Registration.RAcCode;
_scheduleList.Add(schedule);
}
}
catch (Exception ex)
{
throw new NotImplementedException("HANDLE THIS SHIT!", ex);
}
return true;
}
public bool CopyData()
{
try
{
var licensingScheduleRepo = new LicensingScheduleRepository();
//some logic
_desitnation.Commit();
}
catch (Exception ex)
{
//handle exception
}
return true;
}
}
The two main differences between what you're doing and the above is that I'm using Injection Parameters (the ResolvedParameter class) to dynamically resolve instances of objects when they're needed.
This allows me to get Unity to do my entire DI process for me, including resolve my DataCopier. If I add another Datacopier I'd just need to add the new DataCopier type to Unity with a name that matches the appropriate ERunOptions type and I'd be able to resolve the new DataCopier with no change to my code:
container.RegisterType<IDataCopier,RandomDataCopier>("0",new InjectionConstructor(new[] {new ResolvedParameter<IRepositorySession("RandomSource"),new ResolvedParameter<IRepositorySesison>("RandomDestination")}));
and:
ERunOptions dataCopierType = ExtractParams(args);
IDataCopier dataCopier = container.Resolve<IDataCopier(dataCopierType.ToString());
dataCopier.DetectChanges();
dataCopier.ParseData();
dataCopier.CopyData();
Stays the same but can process a ScheduledDataCopier or a RandomDataCopier

Related

C# WebAPI Thread Aborting when Sharing Data Access Logic

I'm getting the following error on my C# Web API: "Exception thrown: 'System.Threading.ThreadAbortException' in System.Data.dll
Thread was being aborted". I have a long running process on one thread using my data access logic class to get and update records being process. Meanwhile a user submits another group to process which has need of the same data access logic class, thus resulting in the error. Here is a rough sketch of what I'm doing.
WebAPI Class:
public IHttpActionResult OkToProcess(string groupNameToProcess)
{
var logic = GetLogic();
//Gets All Unprocessed Records and Adds them to Blocking Queue
Task.Factory.StartNew(() => dataAccessLogic.LoadAndProcess(groupNameToProcess);
}
public IHttpActionResult AddToProcess(int recordIdToProcess)
{
StaticProcessingFactory.AddToQueue(recordIdToProcess);
}
StaticProcessingFactory
internal static ConcurrentDictionary<ApplicationEnvironment, Logic> correctors = new ConcurrentDictionary<ApplicationEnvironment, Logic>();
internal static BlockingCollection<CorrectionMessage> MessageQueue = new BlockingCollection<Message>(2000);
public void StartService(){
Task.Factory.StartNew(() => LoadService());
}
public void LoadService(){
var logic = GetLogic();
if(isFirstGroupOkToProcessAsPerTextFileLog())
logic.LoadAndProcess("FirstGroup");
if(isSeconddGroupOkToProcessAsPerTextFileLog())
logic.LoadAndProcess("SecondGroup");
}
public static GetLogic(){
var sqlConnectionFactory = Tools.GetSqlConnectionFactory();
string environment = ConfigurationManager.AppSettings["DefaultApplicationEnvironment"];
ApplicationEnvironment applicationEnvironment =
ApplicationEnvironmentExtensions.ToApplicationEnvironment(environment);
return correctors.GetOrAdd(applicationEnvironment, new Logic(sqlConnectionFactory ));
}
public static void AddToQueue(Message message, bool completeAdding = true)
{
if (MessageQueue.IsAddingCompleted)
MessageQueue = new BlockingCollection<Message>();
if (completeAdding && message.ProcessImmediately)
StartQueue(message);
else
MessageQueue.Add(message);
}
public static void StartQueue(Message message = null)
{
if (message != null)
{
if(!string.IsNullOrEmpty(message.ID))
MessageQueue.Add(message);
Logic logic = GetLogic(message.Environment);
try
{
var messages = MessageQueue.TakeWhile(x => logic.IsPartOfGroup(x.GroupName, message.GroupName));
if (messages.Count() > 0)
MessageQueue.CompleteAdding();
int i = 0;
foreach (var msg in messages)
{
i++;
Process(msg);
}
}
catch (InvalidOperationException) { MessageQueue.CompleteAdding(); }
}
}
public static void Process(Message message)
{
Var logic = GetLogic(message.Environment);
var record = logic.GetRecord(message.ID);
record.Status = Status.Processed;
logic.Save(record);
}
Logic Class
private readonly DataAccess DataAccess;
public Logic(SqlConnectionFactory factory)
{
DataAccess = new DataAcess(factory);
}
public void LoadAndProcess(string groupName)
{
var groups = DataAccess.GetGroups();
var records = DataAccess.GetRecordsReadyToProcess(groups);
for(int i = 0; i < records.Count; i++)
{
Message message = new Message();
message.Enviornment = environment.ToString();
message.ID = records[i].ID;
message.User = user;
message.Group = groupName;
message.ProcessImmediately = true;
StaticProcessingFactory.AddToQueue(message, i + 1 == records.Count);
}
}
Any ideas how I might ensure that all traffic from all threads have access to the Data Access Logic without threads being systematically aborted?

Generic method for database update

I use following method to update orgnrs in a database:
UpdateService service = new UpdateService()
service.UpdateDocsA(orgnrs);
public void UpdateDocsA(List<string> orgnrs)
{
using (var context = new Data.InexchangeEntitiesA())
{
foreach (string orgnr in orgnrs)
{
try
{
Data.Customers customer = new Data.Customers();
customer.CustNo = orgnr.Trim();
context.Customers.Add(customer);
}
catch (Exception ex)
{
}
}
context.SaveChanges();
}
}
Problem is that I have multiple databases with similar update.
service.UpdateDocsA(orgnrs);
service.UpdateDocsB(orgnrs);
service.UpdateDocsC(orgnrs);
service.UpdateDocsC(orgnrs);
The only difference is in following line:
using (var context = new Data.InexchangeEntitiesA())
using (var context = new Data.InexchangeEntitiesB())
using (var context = new Data.InexchangeEntitiesC())
using (var context = new Data.InexchangeEntitiesD())
I want to create a generic update method. Any ideas how can I achieve it? or how to pass Data.InexchangeEntities to a method?
Assuming that the method signature for InexchangeEntitiesA() and InexchangeEntitiesB() etc. is common why not pass that in to your UpdateDocs method?
If we assume those methods all return an IDataContext object which implements a Customers() method;
UpdateService service = new UpdateService()
service.UpdateDocs(Data.InexchangeEntitiesA, orgnrs);
service.UpdateDocs(Data.InexchangeEntitiesB, orgnrs);
service.UpdateDocs(Data.InexchangeEntitiesC, orgnrs);
service.UpdateDocs(Data.InexchangeEntitiesD, orgnrs);
public void UpdateDocs<T>(Func<T> getContext, List<string> orgnrs) where T : IDataContext
{
using (var context = getContext())
{
foreach (string orgnr in orgnrs)
{
try
{
Data.Customers customer = context.Customers();
customer.CustNo = orgnr.Trim();
context.Customers.Add(customer);
}
catch (Exception ex)
{
}
}
context.SaveChanges();
}
}
Or something like this
public class Customer { }
public interface ISomeFunkyInterface
{
DbSet<Customer> Customers { get; set; }
}
public class DbContextA : DbContext, ISomeFunkyInterface
{
public DbSet<Customer> Customers { get; set; }
}
public void UpdateDocs<T>(List<string> orgnrs)
where T : DbContext, ISomeFunkyInterface ,new()
{
using var context = new T();
foreach (string orgnr in orgnrs)
{
context.Customers.Add(...);
}
context.SaveChanges();
}
service.UpdateDocs(orgnrs, new Data.InexchangeEntitiesA());
service.UpdateDocs(orgnrs, new Data.InexchangeEntitiesB());
service.UpdateDocs(orgnrs, new Data.InexchangeEntitiesC());
service.UpdateDocs(orgnrs, new Data.InexchangeEntitiesD());
service.UpdateDocs(orgnrs, new Data.InexchangeEntitiesE());
...
public void UpdateDocs(List<string> orgnrs, YOURCONTEXTTYPE context)
{
using (context)
{
foreach (string orgnr in orgnrs)
{
try
{
Data.Customers customer = new Data.Customers();
customer.CustNo = orgnr.Trim();
context.Customers.Add(customer);
}
catch (Exception ex)
{
}
}
context.SaveChanges();
}
}
There are multiple ways to achieve that. The most obvious to me is extract what is common and create multiple methods for that:
public void UpdateDocsA(List<string> orgnrs)
{
using (var context = new Data.InexchangeEntitiesA())
{
Perform(context, orgnrs);
}
}
void Perform(DbContext context, List<string> orgnrs)
{
foreach (string orgnr in orgnrs)
{
try
{
Data.Customers customer = new Data.Customers();
customer.CustNo = orgnr.Trim();
context.Customers.Add(customer);
}
catch (Exception ex)
{ }
}
context.SaveChanges();
}
This will reduce the duplicated code massivly. However it still feels ugly, because you still have four Update-methods.
You could also extract what is uncommon and inject a paremeter to switch on:
public void UpdateDocs(string type, List<string> orgnrs)
{
using (var context = GetContext(type))
{
Perform(context, orgnrs);
}
}
DbContext GetContext(string type)
{
return type == "A" ? new Data.InexchangeEntitiesA() :
type == "B" ? new Data.InexchangeEntitiesB() :
type == "C" ? new Data.InexchangeEntitiesC() :
new Data.InexchangeEntitiesD();
}
This does not seem much better, does it? We only have a single method, however it still uses some weird type-switching. Let´s try something more generic - assuming all your entities have some common base-interface or -class:
public void UpdateDocs<T>(List<string> orgnrs) where T: IMyInterface, new()
{
using (var context = new T)
{
Perform(context, orgnrs);
}
}

How to call object from one class to another in C#

I have a problem that I just can't solve on my own. I am new to programming and I would appreciate if you could help me with this issue:
I have a class I would like to inherit from:
namespace rsDeployer.Common.SQLServerCommunication
{
public class RSDatabaseConnectionCreator: LoggerBase
{
public RSProfile profile;
public RSDatabaseConnectionCreator(RSProfile profile)
{
this.profile = profile;
}
public SqlConnection CreateConnection(RSDatabaseNames DatabaseName, bool UseWindowsAuthentication, bool testConnection = false)
{
var connectionString = BuildRSDatabaseConnectionString(DatabaseName, UseWindowsAuthentication);
if (testConnection)
{
return IsConnectionAvailable(connectionString) ? new SqlConnection(connectionString) : null;
}
return new SqlConnection(connectionString);
}
}
}
and I would like to call CreateConnection() in another class to inject to methods to allow me to open connection and then execute scripts.
Edit 1 - class I would like to have it injected to.
public void QueryExecution(string SQLQuery)
{
//here's where I would like to inject it
SqlCommand command = new SqlCommand(SQLQuery, conn);
var file = new StreamWriter(#"D:\Project\rsDeployer\ImportedQuery.txt");
file.WriteLine(command);
file.Close();
}
If this question is way to silly to deserve answer would you just point in the direction where I should read about it?
I hope this question is well asked and clear.
Thanks in advance.
Like this,
public void QueryExecution(string SQLQuery)
{
RSProfile profile = new RSProfile();
RSDatabaseConnectionCreator instance = new RSDatabaseConnectionCreator(profile);
SqlConnection conn = instance.CreateConnection(...);
SqlCommand command = new SqlCommand(SQLQuery, conn);
var file = new StreamWriter(#"D:\Project\rsDeployer\ImportedQuery.txt");
file.WriteLine(command);
file.Close();
conn.Close();
}
You also told that you want to inherit from this class, here is another approach,
public class RSDatabaseConnectionCreator : LoggerBase
{
public virtual object CreateConnection() // by virtual you can override it.
{
return new object();
}
}
public class AnotherClass : RSDatabaseConnectionCreator {
public AnotherClass() {
CreateConnection(); // by inheriting RSDatabaseConnectionCreator , you can reach public functions.
}
public override object CreateConnection() // or you can override it
{
// here might be some user Login check
return base.CreateConnection(); // then you open connection
}
}
Hope helps,
Hope this is what you are requesting for
public class ClassX
{
private RSProfile _rsprofile;
RSDatabaseConnectionCreator _dbConnectionCreator;
private SqlConnection _sqlConnection;
public ClassX()
{
_rsProfile = xxx; // Get the RSProfile object
_dbConnectionCreator = new RSDatabaseConnectionCreator (_rsProfile);
RSDatabaseNames databaseName = yyy; // get the RSDatabaseNames
var useWindowsAuthentication = true;
var testConnection = false;
_sqlConnection = _dbConnectionCreator.CreateConnection(databaseName,useWindowsAuthentication ,testConnection );
}
}
This is how you do it. Apologies for a major blunder in the earlier answer. This one has the connection surrounded by a using.
namespace rsDeployer.Common.SQLServerCommunication
{
public class ConsumerClass
{
public void QueryExecution(string SQLQuery)
{
var profile = new RsProfile();
var rsConnectionCreator = new RSDatabaseConnectionCreator(profile);
using(var sqlConnection = rsConnectionCreator.CreateConnection(...Parameters here...)){
SqlCommand command = new SqlCommand(SQLQuery, sqlConnection );
}
var file = new StreamWriter(#"D:\Project\rsDeployer\ImportedQuery.txt");
file.WriteLine(command);
file.Close();
}
}
}
You can inject the connection creator into the consumer class through the constructor.
public class Consumer
{
private RSDatabaseConnectionCreator _connectionCreator;
// Constructor injection
public Consumer (RSDatabaseConnectionCreator connectionCreator)
{
_connectionCreator = connectionCreator;
}
public void QueryExecution(string SQLQuery)
{
using (var conn = _connectionCreator.CreateConnection(dbName, true, true)) {
if (conn != null) {
...
}
}
}
}
Note: The using statement automatically closes the connection.
Usage
var connectionCreator = new RSDatabaseConnectionCreator(profile);
var consumer = new Consumer(connectionCreator);
consumer.QueryExecution(sqlQuery);
If you want to inject the connection creator at each call of QueryExecution, you can inject it directly into the method as an additional parameter, instead.
public void QueryExecution(string SQLQuery, RSDatabaseConnectionCreator connectionCreator)
{
using (var conn = connectionCreator.CreateConnection(dbName, true, true)) {
if (conn != null) {
...
}
}
}
Usage
var connectionCreator = new RSDatabaseConnectionCreator(profile);
var consumer = new Consumer();
consumer.QueryExecution(sqlQuery, connectionCreator);

Use Rhino Mock to report the function that was called

I have a failing testcase that depends on an external module.
I want to use Rhino Mock to generate a report on called functions.
I created a minimal example that illustrates my problem:
using NUnit.Framework;
using Rhino.Mocks;
using System;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
object liveFastDieYoung = service.HiddenAmongManyCalls();
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch(Exception e)
{
string[] calls = MagicallyGetTheCallsThatWereMadeToTheMock();
foreach(var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private string[] MagicallyGetTheCallsThatWereMadeToTheMock()
{
return new[]
{
"This is where I am lost, I do not know how to get the calls from the repository."
};
}
}
}
I tried to find something online without success.
Do Rhino Mocks record all calls and can I access that list?
Edit:
An attempt to verify Expectations did not work since I am looking for calls I did not expect.
I could build a list of calls using GetArgumentsForCallsMadeOn. I can reflect on the Interface. I started on a method for that but I currently fail to see how I can convert a MethodInfo to an Action<T>.
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
interfaceMethodInfos.Add(property.GetGetMethod());
interfaceMethodInfos.Add(property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
interfaceMethodInfos.Add(method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
Action<Interface> magic = null; //convert methodinfo into action - still missing
var calls = rhinomock.GetArgumentsForCallsMadeOn(magic); //magic is currently null, here be crash
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more){ callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else { callbuilder.Append(parameter.ToString()); }
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
I was able to use reflection to get the output I wanted.
Here is the minimal example where the test fails and the output contains all method calls.
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace StackOverflow_namespace
{
public interface IUsefulService
{
object HiddenAmongManyCalls();
string TestCall2(string arg1, int arg2);
string FULLACCESS { get; set; }
string READONLY { get; }
}
public class ThirdPartyBase
{
private int a = 42;
public ThirdPartyBase(IUsefulService service)
{
service.TestCall2("callA", 1);
service.TestCall2("callB", 1);
object liveFastDieYoung = service.HiddenAmongManyCalls();
service.TestCall2("callA", 2);
service.TestCall2("callB", 2);
var a = service.FULLACCESS;
var b = service.READONLY;
service.FULLACCESS = "some";
liveFastDieYoung.Equals(a);
}
}
public class MyParty : ThirdPartyBase
{
public MyParty(IUsefulService service) : base(service)
{
}
}
[TestFixture]
class StackOverflow
{
[Test]
public void Hypothetical()
{
IUsefulService service = MockRepository.GenerateMock<IUsefulService>();
try
{
var party = new MyParty(service);
}
catch (Exception e)
{
var calls = GetCallsList(service);
foreach (var call in calls)
{
//with my visual studio testrunner for nunit 3 I can investigate stored console output
Console.WriteLine(call);
}
Assert.Fail("Excpexted no exception but was '" + e.GetType().Name + "': " + e.Message);
}
}
private IEnumerable<string> GetCallsList<Interface>(Interface rhinomock)
{
Type interfaceType = typeof(Interface);
List<MethodInfo> interfaceMethodInfos = new List<MethodInfo>();
List<string> returnInfos = new List<string>();
StringBuilder callbuilder = new StringBuilder();
foreach (var property in interfaceType.GetProperties())
{
AddMethodInfoIfValid(interfaceMethodInfos, property.GetGetMethod());
AddMethodInfoIfValid(interfaceMethodInfos, property.GetSetMethod());
}
foreach (var method in interfaceType.GetMethods())
{
AddMethodInfoIfValid(interfaceMethodInfos, method);
}
foreach (var methodinfo in interfaceMethodInfos)
{
int paramcount = methodinfo.GetParameters().Length;
object[] args = new object[paramcount];
Action<Interface> lambdacall = (i) => methodinfo.Invoke(i, args);
var calls = rhinomock.GetArgumentsForCallsMadeOn(lambdacall);
foreach (var call in calls)
{
bool more = false;
callbuilder.Clear().Append(interfaceType.Name).Append('.').Append(methodinfo.Name).Append('(');
foreach (var parameter in call)
{
if (more) { callbuilder.Append(", "); }
if (null == parameter) { callbuilder.Append("<null>"); }
else {
callbuilder
.Append('(').Append(parameter.GetType().Name).Append(")'")
.Append(parameter.ToString()).Append("'");
}
more = true;
}
callbuilder.Append(')');
string callInfo = callbuilder.ToString();
returnInfos.Add(callInfo);
}
}
return returnInfos;
}
private static void AddMethodInfoIfValid(List<MethodInfo> interfaceMethodInfos, MethodInfo methodinfo)
{
if (null != methodinfo)
{
interfaceMethodInfos.Add(methodinfo);
}
}
}
}

How to retrieve data from ebay getFeedback API

I am trying to get some data for a specified user using ebay's getFeedback API and ended up with this code.
namespace one
{
class Program
{
private static ApiContext apiContext = null;
static void Main(string[] args)
{
ApiContext apiContext = GetApiContext();
GeteBayOfficialTimeCall apiCall = new GeteBayOfficialTimeCall(apiContext);
GetFeedbackCall call = new GetFeedbackCall(apiContext);
call.UserID = "abc";
Console.WriteLine(call.GetFeedback().ToString());
Console.ReadKey();
}
static ApiContext GetApiContext()
{
if (apiContext != null)
{
return apiContext;
}
else
{
apiContext = new ApiContext();
apiContext.SoapApiServerUrl = ConfigurationManager.AppSettings["Environment.ApiServerUrl"];
ApiCredential apiCredential = new ApiCredential();
apiCredential.eBayToken = ConfigurationManager.AppSettings["UserAccount.ApiToken"];
apiContext.ApiCredential = apiCredential;
apiContext.Site = SiteCodeType.US;
return apiContext;
}
}
}
}
It prints the following line in console
eBay.Service.Core.Soap.FeedbackDetailTypeCollection
How can I get the original data?
call.GetFeedback() returning collection of FeedbackDetailType members, so you can use foreach to retrieve informations (such as feedback score and other stuff) about all particular feedback.
see complete members list of FeedbackDetailType members
here!
e.g
foreach (FeedbackDetailType feedback in call.GetFeedback())
{
Console.WriteLine(feedback.CommentText);
//and other stuff
}
Or you can use something like that
call.GetFeedback();
Console.WriteLine(call.FeedbackScore);

Categories