Okay, I have yet another Code Contracts question. I have a contract on an interface method that looks like this (other methods omitted for clarity):
[ContractClassFor(typeof(IUnboundTagGroup))]
public abstract class ContractForIUnboundTagGroup : IUnboundTagGroup
{
public IUnboundTagGroup[] GetAllGroups()
{
Contract.Ensures(Contract.Result<IUnboundTagGroup[]>() != null);
Contract.Ensures(Contract.ForAll(Contract.Result<IUnboundTagGroup[]>(), g => g != null));
return null;
}
}
I have code consuming the interface that looks like this:
public void AddRequested(IUnboundTagGroup group)
{
foreach (IUnboundTagGroup subGroup in group.GetAllGroups())
{
AddRequested(subGroup);
}
//Other stuff omitted
}
AddRequested requires a non-null input parameter (it implements an interface which has a Requires contract) and so I get a 'requires unproven: group != null' error on the subGroup being passed into AddRequested. Am I using the ForAll syntax correctly? If so and the solver simply isn't understanding, is there another way to help the solver recognize the contract or do I simply need to use an Assume whenever GetAllGroups() is called?
The Code Contracts User Manual states, "The static contract checker does not yet deal with quantiers ForAll or Exists." Until it does, it seems to me the options are:
Ignore the warning.
Add Contract.Assume(subGroup != null) before the call to AddRequested().
Add a check before the call to AddRequested(). Maybe if (subGroup
== null) throw new InvalidOperationException() or if (subGroup != null)
AddRequested(subGroup).
Option 1 doesn't really help. Option 2 is risky because it will circumvent the AddRequested() Requires contract even if IUnboundTagGroup.GetAllGroups() no longer ensures that post-condition. I'd go with option 3.
Related
EDIT:
I just realized that SaveChangesAsync returning 0 doesn't mean that it failed, entity framework will always throw exception when something fails so the check if SaveChanges == 0 is redundant! Save changes should always return 1 in the example below, if something fails then exception will be thrown.
However there are cases when something else is used and it's not entity framework so is this question for.
Servers can fail, when putting all my data access code in controllers I can handle it this way:
[HttpPost]
public async Task<ActionResult<Item>> CreateAsync([FromBody] Item item)
{
await _dbContext.AddAsync(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return CreatedAtAction(nameof(GetAsync), new { id = item.Id }, item);
}
How should I handle it when my data access is encapsulated in a service layer?
public class ItemsService
{
public async Task<Item> CreateAsync(Item item)
{
await _dbContext.AddAsync(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
return null;
}
return item;
}
}
Then it would be used like that:
[HttpPost]
public async Task<ActionResult<Item>> CreateAsync([FromBody] Item item)
{
// model state validation skipped for the sake of simplicity,
// that would return BadRequest or some more valuable information
var item = await _itemsService.CreateAsync(item);
if (item == null)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return CreatedAtAction(nameof(GetAsync), new { id = item.Id }, item);
}
Maybe this works for fine creating because there are only 2 status codes but let's consider updating where there can be more than 2 possible errors like:
Not found (404)
Internal server error(500)
Ok (200)
Code without services:
[HttpPut("{id}")]
public async Task<ActionResult<Item>> UpdateAsync(int id, [FromBody] Item itemToUpdate)
{
var item = await _dbContext.Items.FindAsync(id);
if (item == null)
{
return NotFound();
}
// update item with itemToUpdate
//...
await _dbContext.Update(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return item;
}
Now with services this can't be properly handled:
public class ItemsService
{
public async Task<Item> UpdateAsync(Item updateItem)
{
var item = await _dbContext.Items.FindAsync(id);
if (item == null)
{
return null;
}
//change some properties and update
//...
_dbContext.Items.Update(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
// what now?
}
return item;
}
}
because it always returns null and there's no way to tell if the item was not found or the saving failed.
How can I handle it properly?
Note: I didn't add DTO or anything like that to keep this example simple.
Your service is responsible for catching all the exceptions it knows how to handle and handles those. All the other exceptions should be reported throught some kind of IServiceResult<T> providing both bool IsSuccessful and AggregatedException Exceptions { get; }. So rather than throw you let the highest level to decide how to react. It's actually the best approach from many points of view, including: purity of your functions (which is a key concept for easy parallezation, isn't it important for server?), clean and maintanable code (consumers of the service should not know/care that much: they just verify whether result is successful and consume the result; otherwise dig into aggreaged exception; might make sense to implement your own type of exception providing methods suitable for needs of your project), ability to procceed on higher-order-functions, which are responsible for actual error handling; take rX as a popular example: .OnError(Action<Exception> handler). There are much more than this, however I don't like to make the answer longer that it needs to be.
As a side note. Make sure you read an introductory lever articles about Maybe and Either monads from Haskell programming language; in case you'd prefer F# more, you can try to seek for Some and Either respectively. There you can find useful methods like .Map(...) and see nice ways to combine/aggregate those in efficient way.
Good luck.
The code with the service is far better. The controller sould delegate business logic to the service layer.
To make your implementation of the service layer more better, you should:
throw custom exceptions when something wrong happened in your service. Example : throw ItemNotFoundExcption instead of returning null. ItemUpdateException when updates failed.
in your controller you need to catch all possible custom exceptions that might happenned and do what need to be done like returning NotFound() for ItemNotFoundException and BadRequest() for ItemUpdateException.
the latter point can be made through custom action filter which helps you make your controller's actions more lean.
It's actually a pretty big topic and there are dozens of options to do it.
I prefer to throw exceptions. You can create your own classes for that or use .net ones. You can have NotFoundException, InternalServerError and etc. Each class can have StatusCode and Message field or whatever you want. Next you need to implement exception filter for asp.net which will handle all exceptions and return response with status code that can be retrieved from exception class.
Another option maybe simpler. You can create a class that will contain StatusCode and object as a result so you will return it from your methods. It's a way to return more then just null or object from your methods.
Few good articles:
Exceptions or error codes
https://www.hanselman.com/blog/GoodExceptionManagementRulesOfThumb.aspx
http://codebetter.com/karlseguin/2006/04/05/understanding-and-using-exceptions/
I have this method in C# that looks like I should really refactor it . Should I use a design pattern ? Too much repetition is what I see NOW and especially as MORE conditional if statements get added
Change to a method?
public void CreateOrUpdateReportDefinition(ReportGroupSubReport reportGroupSubReport, bool isNew, int report)
{
if (report == 1)
{
var entity = _envyUnitOfWork.ReportDefinitions.GetById(reportGroupSubReport.Id) ?? new ReportDefinition();
if (isNew)
entity.SetNew();
_envyUnitOfWork.ReportDefinitions.InsertOrUpdate(entity, true);
}
else if (report == 2)
{
var entity = _envyUnitOfWork.TraxReports.GetById(reportGroupSubReport.Id) ?? new TraxReport();
if (isNew)
entity.SetNew();
_envyUnitOfWork.TraxReports.InsertOrUpdate(entity, true);
}
Mapper.Map(reportGroupSubReport, entity);
_envyUnitOfWork.Commit();
}
So what I would do is to put every single conditional behavior into separate method. To avoid repetition you could use the template method pattern. You should also declare your report variable before all if statements so that it would be accessible for the Mapper.Map().
Edit:
Ok, so assuming that both _envyUnitOfWork.TraxReports and _envyUnitOfWork.ReportDefinitions share some common generic interface (which I named Repository in code) defining GetById and InsertOrUpdate methods, you do not need to use any design patterns - simple generic method will do the job. Here is example of the code:
private void createOrUpdateReportDefinition<Report>(ReportGroupSubReport reportGroupSubReport, bool isNew, Repository<Report> repository/*, Action<Report> insertOrUpdate*/) where Report : new()
{
var entity = repository.GetById(reportGroupSubReport.Id) ?? new Report();
if (isNew)
entity.SetNew();
repository.InsertOrUpdate(entity, true);//insertOrUpdate(entity, true);
Mapper.Map(reportGroupSubReport, entity);
_envyUnitOfWork.Commit();
}
public void CreateOrUpdateReportDefinition(ReportGroupSubReport reportGroupSubReport, bool isNew, int report)
{
if (report == 1)
{
createOrUpdateReportDefinition(reportGroupSubReport, isNew, _envyUnitOfWork.ReportDefinitions/*, _envyUnitOfWork.ReportDefinitions.InsertOrUpdate*/);
}
else if (report == 2)
{
createOrUpdateReportDefinition(reportGroupSubReport, isNew, _envyUnitOfWork.TraxReports/*, _envyUnitOfWork.TraxReports.InsertOrUpdate*/);
}
}
Please take under consideration this code is dealing only with one issue in your code which was the code duplication, there are still few things you could improve like removing int report parameter from the method either by dividing it into few methods or at least by replacing it with some enum with meaningful name. I would also suggest the same (dividing the methods) for the bool isNew parameter, since using it means your function doesn't do one thing only which is against single responsibility principle from SOLID - you can read more about it here.
The following refactoring pattern might give you some clues as to how you could manage the proliferating conditional problem: https://sourcemaking.com/refactoring/replace-conditional-with-polymorphism
Edit: The easiest way to do this would be defining an Interface that both TraxReports and ReportDefinition implement that has a InsertOrUpdate method.
I have this piece of code that consumes too much vertical space and it's too verbose.
if (property == null)
{
throw new XamlParseException($"Cannot find a property named \"{Name}\" in the type {underlyingType}");
}
Isn't there an equivalent method, but more legible and compact?
Something in the shape of
ThrowIfNull<XamlParseException>(message)
You can always create an extension method:
public static class ClassContracts {
public static void ThrowIfNull(this Object item)
{
if(item == null) throw new XamlParseException("Your message here", null);
}
}
This way you use up less space which is what you were talking about, and you can use the code over and over whenever you need it. I have a library of these for testing for nulls etc. I like doing it this way over Code Contracts, because that requires the binary rewriter and depending on your environment, your build system (if you have one) may not support doing that. Ultimately, Code Contracts do more than just this, but in a pinch this offers a quick and concise way of checking for nulls and other conditions easily in code as you can create other ones like:
public static void CheckForCondition <T>(this T item, Predicate<T> p, Func<Your_Exception_Type> createException)
{
if(p(item)){throw createException();}
}
With this base method, you can then create other ones and create overloads, etc. have the predicate, or the exception method already created.
public static void CheckForNullCondition<T>(this T item)
{
item.CheckForCondition(x => x == null,
() => new Exception("Item is null"));
}
Extension Methods
I have no knowledge of such method but you can either create it by yourself or just move message to the resources file/internal constant (of course if the space taken by it is the case).
Extension approach is also viable option if it is acceptable for you (I mean having such extension for PropertyInfo or any other type).
I do not want to disable the warnings completely, just when it's in an Assert statement.
So for example if I have the following two lines
var someObject = GetObject();
Assert.IsNotNull(someObject, "someObject should not be null");
Assert.AreEqual(expectedValue, someObject.SomeProperty);
I'll get the possible null reference warning on the second line on someObject.SomeProperty. Is it possible to disable the warning when it is within a certain call, like Assert.AreEqual?
Since this is an issue with a lot of unit tests, I don't want to litter the tests with the ReSharper disable code.
Right now the only option I can think of is to change every Assert.IsNotNull call to be
var someObject = GetObject();
if(someObject == null)
{
Assert.Fail("someObject is null");
return;
}
Although this kind of seems to defeat the purpose of having Assert.IsNotNull in the first place. Just wondering if there is a better way.
I don't know the specific library you use, but I'd try something like
Assert.IsTrue(someObject != null);
or, for the sake of completeness,
Assert.IsNotNull(someObject, "someObject must not be null");
Assert.IsNotNull(someObject.SomeProperty, "SomeProperty must not be null either");
Assert.SomethingElse(...);
Add this to your project:
public static class AssertionsExtensions
{
[NotNull]
public static TSubject ShouldNotBeNull<TSubject>([CanBeNull] this TSubject source,
[CanBeNull] string because = "", [CanBeNull] [ItemCanBeNull] params object[] reasonArgs)
{
source.Should().NotBeNull(because, reasonArgs);
// ReSharper disable once AssignNullToNotNullAttribute
return source;
}
}
Then use it like this, for example:
// Assert
succeeded.Should().Be(true, "<USB loopback cable must be connected and COM port must be correct.>");
DeviceStatus deviceStatusNotNull = testRunner.Result.ShouldNotBeNull();
deviceStatusNotNull.DeviceAddress.Should().Be(deviceAddress);
deviceStatusNotNull.IsInNetwork.Should().Be(true);
If I am not mistaken, your problem is that resharper gives warnings when null is not checked foreach object. You can modify resharper rules not to give null warnings in test classes.
Here is a link about changing ReSharper naming style for test methods.
Use NUnit instead of MBUnit. NUnit's implementation of Assert.IsNotNull() is picked up as guaranteeing not null whereas MBUnit's is not.
You can use R# external annotations to suppress the warnings (see http://grahamrhay.wordpress.com/2011/01/09/external-annotations/).
What version of MbUnit/Gallio are you using?
You can use ContractAnnotations to indicate the execution stops if parameter is null. See jetbrains contract annotations. Sample class:
public static class FluentExtensions
{
//see: https://www.jetbrains.com/help/resharper/2017.3/Contract_Annotations.html
[ContractAnnotation("null => stop")]
public static void ShouldNotBeNull(this object objToTest)
{
objToTest.Should().NotBeNull();
}
}
Usage:
doc.ShouldNotBeNull();
doc.Content.ShouldNotBeNull();
I have some factory method
public T Create<T> () where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
T result = this.unityContainer.Resolve<T>();
return result;
}
The I try to build the project i get the warning:
CodeContracts: ensures unproven: Contract.Result() != null
I understand that IUnityContainer interface does not have any contracts so Code Contracts think that varible may be null and there is no way to prove that Create() will return not null result.
How in this case I can make Code Contracts belive that result variable is not null?
I first tried to call Contract.Assert
public T Create<T> () where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
T result = this.unityContainer.Resolve<T>();
Contract.Assert(result != null);
return result;
}
But it takes me another warning:
CodeContracts: assert unproven
I tried make check for null and this makes all warnings gone:
public T Create<T> () where T : class
{
Contract.Ensures(Contract.Result<T>() != null);
T result = this.unityContainer.Resolve<T>();
if (result == null)
{
throw new InvalidOperationException();
}
return result;
}
But i'm not sure this is good solution to throw exception manually. May be there is some way to solve problem using Code Contracts only?
Thank you.
I think you want Contract.Assume:
Contract.Assume(result != null);
From the docs:
Instructs code analysis tools to assume that the specified condition is true, even if it cannot be statically proven to always be true.
This will still validate the result at execution time if you have the rewriter appropriately configured.
Like if((result ?? 0) == 0){}
To make this more clear (readable) you can define an extension method.
Edit
#allentracks answer is more precise for your question