One Method Accepting Two Different Objects - c#

I have two methods, one to check-in internal users and another to check-in external users. The method is the same except for the object (see code). I was wondering if it's possible to have one method that would accept both objects. I want to pass a parameter that says if it's internal or external, and based on that I want to call the respective object and save it. Not sure if it's possible.
public JsonResult CheckInInternal(int ID)
{
var e = EventInternal.Get(ID, EventInternal.FetchType.ID);
if (e.ID == 0)
{
throw new Exception("Registration ID not found.");
}
if (DateTime.Now.Date > e.EventDetail.StartTime.Date)
{
throw new Exception("Check-in has been closed for this class!");
}
e.CheckedIn = true;
e.Save();
return Json(new { success = true, message = "Success!" });
}
public JsonResult CheckInExternal(int ID)
{
var e = EventExternal.Get(ID, EventExternal.FetchType.ID);
if (e.ID == 0)
{
throw new Exception("Registration ID not found.");
}
if (DateTime.Now.Date > e.EventDetail.StartTime.Date)
{
throw new Exception("Check-in has been closed for this class!");
}
e.CheckedIn = true;
e.Save();
return Json(new { success = true, message = "Success!" });
}

Not saying this is the best way, but you can use Reflection
public enum CallType
{
Internal, External
}
public JsonResult CheckInInternalOrExternal(int ID, CallType type)
{
object e = type == CallType.Internal? EventInternal.Get(ID, EventInternal.FetchType.ID) as object : EventExternal.Get(ID, EventExternal.FetchType.ID) as object;
var idProperty = e.GetType().GetProperty("ID");
var idValue = Convert.ToInt32(IdProperty.GetValue(e));
if (idValue == 0)
{
throw new Exception("Registration ID not found.");
}
if (DateTime.Now.Date > e.EventDetail.StartTime.Date)
{
throw new Exception("Check-in has been closed for this class!");
}
var checkedInProperty = e.GetType().GetProperty("CheckedIn");
checkedInProperty.SetValue(e, true);
var saveMethod = e.GetType().GetMethod("Save");
saveMethod.Invoke(e);
return Json(new { success = true, message = "Success!" });
}
But as some commenters are saying, Interface or Generics is the best solution. Depending on your scenario.

Related

How to implement IConvertible

I have some test code to check if 2 sides are equal.
public void GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos()
{
// Arrange
var companyRequset = new CompanyRequest();
// Act
var companyDtos = _datlinqServiceMock.GetCompanies(companyRequset);
// Assert
Assert.IsTrue(companyDtos != null && companyDtos.Any());
Assert.AreEqual(DatlinqServiceMock.CompanyName, companyDtos.FirstOrDefault().Name);
}
That calls this.
public class DatlinqServiceMock: DatlinqService
{
public static string CompanyName = "Company_Test";
public override T GetApi<Q,T>(string apiMethod, Q request)
{
var companyList = new List<Company>()
{
new Company(){ Name = CompanyName}
};
return (T)Convert.ChangeType(companyList, typeof(T));
}
}
GetCompanies:
public List<Company> GetCompanies(CompanyRequest request)
{
if (request == null)
{
return new List<Company>();
}
var searchCompany = new SearchCompanyRequest();
searchCompany.Query = request.Name;
searchCompany.DatlinqKey = ConfigurationManager.AppSettings["Datlinq_Key"];
var searchCompanyResponse = GetApi<SearchCompanyRequest,SearchCompanyResponse>(DatlinqApiMethod.SearchCompany, searchCompany);
var companies = searchCompanyResponse.Result
.Select(c => new Company { Id = c.Id, Name = c.Name })
.ToList();
return companies;
}
GetApi:
public virtual T GetApi<Q,T>(string apiMethod, Q request)
{
var result = default(T);
try
{
var url = String.Format("{0}{1}", _apiUrl, apiMethod);
if (request != null)
{
url = QueryHelpers.AddQueryString(url, request.ToDictionary());
}
var apiResponse = _httpClient.GetAsync(url).Result;
if (apiResponse.IsSuccessStatusCode)
{
string apiResponseString = apiResponse.Content.ReadAsStringAsync().Result;
if (!string.IsNullOrEmpty(apiResponseString))
{
result = JsonConvert.DeserializeObject<T>(apiResponseString);
}
}
}
catch (Exception)
{
// do something
}
return result;
}
And I get an error when I execute the first test
Message: 
Test method Lavazza.ContractTool.Datlinq.Tests.Services.DatlinqServiceTests.GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos threw exception:
System.InvalidCastException: Object must implement IConvertible.
Stack Trace: 
Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
Convert.ChangeType(Object value, Type conversionType)
DatlinqServiceMock.GetApi[Q,T](String apiMethod, Q request) line 79
DatlinqService.GetCompanies(CompanyRequest request) line 23
DatlinqServiceTests.GetCompanies_WithCorrectCompanyRequest_ReturnCompanyDtos() line 32
I hope this is enough code to know what the problem/solution is if not let me know what you need.
To answer some question asked below.
Dai: I am trying to find what this is and why I need it because it came up in the error but the microsoft docs don't make it clear for me.
Jeroen: It is kind of a legacy project so I can't/won't add extra dependencies.
The "issue" here is that your GetApi method is designed to return a sort of generic response - in this specific case SearchCompanyResponse - but you're trying to override it to return a List<Company> which is wrong because that is what your GetCompanies method does (ie turn a SearchCompanyResponse to a List<Company>).
Suffice it to say this has nothing to do with implementing IConvertable.
What you would be better off doing is serializing a SearchCommpanyResponse that you wish to use for testing to a file, and using that file-based response for your testing.
That way your overridden "Mock" would be
public override T GetApi<Q,T>(string apiMethod, Q request)
{
return JsonConvert.DeserializeObject<T>(File.ReadAllText("mytestfile.json"));
}

can't insert data to table in mvc c#

i have 2 actions .. one for User and i can add data to User table but for Order table my code didn't works and got catch error
this is my user code (Action in Controller)
[HttpPost]
public ActionResult Register(User user)
{
UserRepository blUser = new UserRepository();
if (ModelState.IsValid)
{
if (blUser.Add(user))
{
return Json(new JsonData() { Success = true });
}
else
{
return Json(new JsonData() { Success = false });
};
}
else
{
return Json(new JsonData() { Success = false });
}
}
and (UserRepository):
public class UserRepository : IDisposable
{
private HairCut.Models.MVCHairDresserDBEntities db = null;
public UserRepository()
{
db = new HairCut.Models.MVCHairDresserDBEntities();
}
public bool Add(HairCut.Models.User entity, bool autoSave = true)
{
try
{
db.Users.Add(entity);
if (autoSave)
return Convert.ToBoolean(db.SaveChanges());
else
return false;
}
catch
{
return false;
}
}
i just change User word to Order but when try to insert data to table i got catch and return false
Order code:
[HttpPost]
public ActionResult Reserve(int select, int user,int hdId)
{
Order order = new Order();
order.HairDresserId =hdId;
order.UserId = user;
order.timeCome = (select).ToString();
order.timeNow = DateTime.Now.ToString("dddh");
order.confirm = true;
OrderRepository blOrder = new OrderRepository();
if (blOrder.Add(order))
{
return Json(new JsonData() { Success = true });
}
else
{
return Json(new JsonData() { Success = false });
}
}
OrderRepository is similar UserRepository. so why cant insert ? where is my wrong ?
every time use breackpoint and debug my codes got catch in code return Convert.ToBoolean(db.SaveChanges());
OrderRepository have 2 foreignkey. when i checked entity quick watch, helper show me 2 extra field ( User and HairDresser with null value ) .. maybe i need set value to these ?
or maybe need create MetaData class to check validation like User values ( but i don't think this is my problem )

C# Mongo Query efficiency

I have a FilterDefinition build that will look for an address based on the properties that are not empty.
public static FilterDefinition<TU> FindPointByAddress<TU>(Address address)
{
var filterBuilder = Builders<TU>.Filter;
var filterItems = new List<FilterDefinition<TU>>();
if (!String.IsNullOrWhiteSpace(address.Street))
{
filterItems.Add(filterBuilder.Eq("Address.Street", address.Street));
}
if (!String.IsNullOrWhiteSpace(address.City))
{
filterItems.Add(filterBuilder.Eq("Address.City", address.City));
}
if (!String.IsNullOrWhiteSpace(address.StateProvince))
{
filterItems.Add(filterBuilder.Eq("Address.StateProvince", address.StateProvince));
}
if (!String.IsNullOrWhiteSpace(address.PostCode))
{
filterItems.Add(filterBuilder.Eq("Address.PostCode", address.PostCode));
}
return filterBuilder.And(filterItems);
}
IMO this query feels dirty, is there a better way to build this type of query or is this the correct way?
A few days ago I had a similar situation. I wrote a simple method that takes a field name and field value as a string.
public void AddEqualCompareFilter(string fieldName, string fieldValue)
{
if (String.IsNullOrEmpty(fieldValue) == false) {
if (Filter != null) {
Filter = Filter & Builders<TranslationsDocument>.Filter.Eq(fieldName, fieldValue);
}
else {
FilterCount++;
Filter = Builders<TranslationsDocument>.Filter.Eq(fieldName, fieldValue);
}
}
}
I am then using this snippet to decide based on FilterCount:
if (FilterCount > 0) {
Result = collection.Find(Filter).ToListAsync().GetAwaiter().GetResult();
return true;
}
else {
Result = collection.Find(new BsonDocument()).ToListAsync().GetAwaiter().GetResult();
return true;
}

How to create multiple POST methods on an Azure Mobile Service?

I have an Azure Mobile Service with multiple controllers. One of my controllers (TestSetController) has some extra methods to check on insert.
Problem I need to solve: The TestSet table has two different types of TestSets, one for a local team and another for a field team. The table contains data for both and the records are differentiated by a "TeamType" field which says if the local team inserted the TestSet or the field team did. On any insert I want to check if a similar TestSet exists that was inserted by the other team. I want to compare the TestSets (if found) then do some other inserts/updates on the same table if the TestSets are different.
However, I keep getting this error:
Exception=System.InvalidOperationException: Multiple actions were found that match the request:
PostTestSetDTO on type sbp_ctService.Controllers.TestSetController
CheckForDiscrepancy on type sbp_ctService.Controllers.TestSetController
CompareTestPointAttempts on type sbp_ctService.Controllers.TestSetController
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext(), Id=f07761ae-1be7-4f00-90b0-685dd0c108f3, Category='App.Request'
Here's my controller:
public class TestSetController : TableController<TestSetDTO>
{
private Context context;
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
context = new Context();
DomainManager = new SimpleMappedEntityDomainManager<TestSetDTO, TestSet>(context, Request, Services, testset => testset.Id);
}
// GET tables/TestSet
[QueryableExpand("TestPointAttempts")]
public IQueryable<TestSetDTO> GetAllTestSetDTO()
{
return Query();
}
// GET tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<TestSetDTO> GetTestSetDTO(string id)
{
return Lookup(id);
}
// PATCH tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<TestSetDTO> PatchTestSetDTO(string id, Delta<TestSetDTO> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public async Task<IHttpActionResult> PostTestSetDTO(TestSetDTO item)
{
TestSet testSet = AutoMapper.Mapper.Map<TestSetDTO, TestSet>(item);
this.CheckForDiscrepancy(testSet);
TestSetDTO current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task DeleteTestSetDTO(string id)
{
return DeleteAsync(id);
}
public TestSet CheckForDiscrepancy(TestSet sourceTestSet)
{
// Set the team type to search for opposite to the one being posted.
string searchTeamType = null;
if (sourceTestSet.TestTeamType == "D")
{
searchTeamType = "F";
}
if (sourceTestSet.TestTeamType == "F")
{
searchTeamType = "D";
}
var testSetTable = context.TestSets;
TestSet foundTestSet = (from ts in testSetTable
where ts.TileId == sourceTestSet.TileId && ts.ScenarioId == sourceTestSet.ScenarioId && ts.TestTeamType.StartsWith(searchTeamType)
select ts).SingleOrDefault();
// If no other test set was found from the opposing team then the test set is missing.
// Else a testSet was found so continue with checks.
if (foundTestSet == null)
{
sourceTestSet.DiscrepancyTypeId = DiscrepancyType.Missing.ToString();
}
else
{
var testPointAttemptTable = context.TestPointAttempts;
// Get all of the associated TestPointAttempts for each testSet.
sourceTestSet.TestPointAttempts = (from tpa in testPointAttemptTable
where tpa.TestSetId == sourceTestSet.Id
orderby tpa.TestAttemptNumber
select tpa).ToList<TestPointAttempt>();
foundTestSet.TestPointAttempts = (from tpa in testPointAttemptTable
where tpa.TestSetId == foundTestSet.Id
orderby tpa.TestAttemptNumber
select tpa).ToList<TestPointAttempt>();
bool matchingTestSets = CompareTestPointAttempts(sourceTestSet.TestPointAttempts, foundTestSet.TestPointAttempts);
if (!matchingTestSets)
{
sourceTestSet.DiscrepancyTypeId = DiscrepancyType.Discrepancy.ToString();
sourceTestSet.DiscrepancyTestSetId = foundTestSet.Id;
}
}
return sourceTestSet;
}
public bool CompareTestPointAttempts(IEnumerable<TestPointAttempt> sourceTPAs, IEnumerable<TestPointAttempt> foundTPAs)
{
bool pass = false;
// First check if the total number of testPointAttempts are the same
if (sourceTPAs.Count() == foundTPAs.Count())
{
foreach (TestPointAttempt sTpa in sourceTPAs)
{
bool foundMatch = false;
foreach (TestPointAttempt fTpa in foundTPAs)
{
if (sTpa.TestAttemptNumber == fTpa.TestAttemptNumber)
{
if (sTpa.TalkIn == fTpa.TalkIn && sTpa.TalkOut == fTpa.TalkOut)
{
foundMatch = true;
}
}
}
if (!foundMatch)
{
return pass;
}
}
// The foreach loop finished successfully meaning all matches were found
pass = true;
}
return pass;
}
/// <summary>
/// The type of discrepancy a TestSet can have.
/// </summary>
public enum DiscrepancyType
{
Discrepancy,
Missing,
None
}
}
}
I'm using Data Transfer Objects (DTOs) to map between the entity models. Any help would be appreciated. I've looked at some different answers on StackOverflow for ASP.NET but they all talk about updating the config.Routes. This is for an Azure Mobile Service which might have different requirements than a simple ASP.NET website though.
It was as simple as making the two methods private and leaving the actual POST method as public. ASP.NET will only make routes automatically for public methods.

How can i identify which condition failed in a if statement with multiple OR conditions?

How can i identify which condition failed in a if statement with multiple OR conditions.example as following.
if ((null == emailNotificationData || string.IsNullOrEmpty(emailNotificationData.Sender))
|| null == emailNotificationData.ToRecipients)
{
LogProvider.Log(typeof(Notification), LogLevel.Error, "Error sending the email notification 'Here i want to log failed argument'");
return;
}
You can't, without rechecking each condition. I'd just write that as:
if (emailNotificationData == null)
{
// This is a helper method calling LogProvider.Log(...)
LogEmailNotificationError("No email notification data");
return;
}
if (string.IsNullOrEmpty(emailNotificationData.Sender))
{
LogEmailNotificationError("No sender");
return;
}
if (emailNotificationData.ToRecipients == null)
{
LogEmailNotificationError("No recipients");
return;
}
You could extract this into a ValidateAndLog extension method on your notification data type though - making it an extension method means you can handle it being null, too:
// ValidateAndLog returns true if everything is okay, false otherwise.
if (!emailNotificationData.ValidateAndLog())
{
return;
}
That way it doesn't need to clutter up other code.
Note that there's almost never any benefit in C# to writing:
if (null == x)
... unless you're actually comparing Boolean values, the "normal" reason for preferring the constant-first comparison (catching a typo of = for ==) doesn't apply, as if (x = null) wouldn't compile anyway.
Either use multiple ifs or meaningful bool variables:
bool noEmailData = emailNotificationData == null;
bool noEmailSender = string.IsNullOrEmpty(emailNotificationData.Sender);
if(noEmailData || noEmailSender)
{
string msg = string.Format("Error sending the email notification: {0} {1}."
, noEmailData ? "No email-data available" : ""
, noEmailSender ? "No email-sender available" : "");
LogProvider.Log(typeof(Notification), LogLevel.Error, msg);
}
That increases readability in general.
You can create a validation rule to check the emailNotificationData.
public class Rule<T>
{
public Func<T, bool> Test { get; set; }
public string Message { get; set; }
}
Then you create a class where you define the rules for your emailNotificationData.
public class EmailNotificationValidationRules
{
public static IEnumerable<Rule<EmailNotificationData>> Rules
{
get
{
return new List<Rule<EmailNotificationData>>
{
new Rule<EmailNotificationData> { Test = data => data != null, Message = "No email notifacation data" },
new Rule<EmailNotificationData> { Test = data => !string.IsNullOrEmpty(data.Sender), Message = "No sender" },
new Rule<EmailNotificationData> { Test = data => data.ToRecipients != null, Message = "No recipients" }
};
}
}
}
Now you can check the your object with this code
bool isValid = EmailNotificationValidationRules.Rules.All(rule => rule.Test(emailNotificationData));
if (isValid == false)
{
var failedRules = EmailNotificationValidationRules.Rules.Where(rule => rule.Test(emailNotificationData) == false);
var text2Log = failedRules.Aggregate(new StringBuilder(), (builder, rule) => builder.AppendLine(rule.Message), builder => builder.ToString());
}
The field text2log contains only the messages of the failed rules.

Categories

Resources