C# syntax question: builder.Services.AddControllers - c#

I'm trying to understand the following syntax
builder.Services.AddControllers(option =>
{
option.ReturnHttpNotAcceptable = true;
});
As far as I understand it it creates an Action delegate with an object (option) of type MvcOptions. The following approaches should be the same, are they?
// Approach 1
Action<MvcOptions> optionDelegate = (MvcOptions option) =>
{
option.ReturnHttpNotAcceptable = true;
};
builder.Services.AddControllers(optionDelegate);
// Approach 2, shorter
builder.Services.AddControllers((MvcOptions option) =>
{
option.ReturnHttpNotAcceptable = true;
});
// Approach 3, even more shorter
builder.Services.AddControllers(option =>
{
option.ReturnHttpNotAcceptable = true;
});

Related

C# how to define an anonymous type with IQueryable?

Depending on a switch/case a variable is set to an EF chaining.
but I cannot figure how to define the variable groupByLeadIdQuery
IQueryable groupByLeadIdQuery = null;
switch (...)
{
case ...:
{
groupByLeadIdQuery = context.HistoryRecords.GroupBy(h => h.ProductId)
.Select(g => new
{
Id = g.Key,
Retributions = g.Sum(s => s.Retribution),
});
}
break;
case ...:
{
groupByLeadIdQuery = null;
}
...
}
later in the code, I am processing the results depending on the variable is null or not
if (groupByLeadIdQuery2 != null)
{
var list = groupByLeadIdQuery2.ToList(); <<<<<<<<<<<<<<<<<<
...
}
the compiler complains: IQueryable does not contain a definition of ToList
I tried
IQueryable<T> groupByLeadIdQuery = null;
IQueryable<Anonymous> groupByLeadIdQuery = null;
IQueryable<'a> groupByLeadIdQuery = null;
var groupByLeadIdQuery = null;
nothing works.
can you enlight me on this?
thanks for your help
from King King
groupByLeadIdQuery2.Cast<dynamic>().ToList()
works like a charm
For having ToList method you should have define your IQueryable variable as List. For example IQueryable<Product> or something Like this. If there is not a certain Type you can use just var and get your anonymous type.
In your case I think easiest solution will be setting a default value and than updating by cases. But in this case you have to set same anonymous type for each cases, otherwise you have to cast types.
var groupByLeadIdQuery = context.HistoryRecords.GroupBy(h => h.ProductId)
.Select(g => new
{
Id = g.Key,
Retributions = g.Sum(s => s.Retribution),
});
switch (...)
{
case ...:
{
groupByLeadIdQuery = ...;
}
break;
case ...:
{
groupByLeadIdQuery = null;
}
...
}
If this is not solving your problem you should use interfaces, an interface which contains the properties you need, or dynamics maybe.
Switch expressions may be a good option here. The fundamental problem is that you need the <T> in IQueryable<T>, but it is "unpronounceable", so you can only use var to declare such, but:
var query = whatever switch {
SomeCase => your.Query.Here...,
_ => null,
};
Note that while you can have as many case lines as you need, they must all have the same shape for this to work.
You can make generic Group By method some thing like this:
public async Task<List<T>> GetGroupByResult<T>(string groupByItem) where T : class
{
var groupByLeadIdQuery = _dbContext.Set<T>();
switch (groupByItem)
{
case "ProductId":
{
groupByLeadIdQuery = groupByLeadIdQuery.GroupBy(h => h.ProductId)
.Select(g => new
{
Id = g.Key,
Retributions = g.Sum(s => s.Retribution),
});
break;
}
case "Other":
{
groupByLeadIdQuery = ...;
break;
}
default:
{
groupByLeadIdQuery = null;
}
}
if (groupByLeadIdQuery != null)
return await groupByLeadIdQuery.ToListAsync();
return default;
}
It can use for any of your entities.

How to initialize var when it is used for different things in a method

I have a method in my controller that is performing some logic based on data submitted and my varitem should be assigned to different results?
For example my controller's method is something like this:
public ActionResult Index(SearchCriteria criteria)
{
var db = new EbuyDataEntities();
//criteria.SearchKeyword = "movie";
if (!string.IsNullOrEmpty(criteria.SearchKeyword))
{
var auctionData = db.Auctions.First(q => q.Description.Contains(criteria.SearchKeyword));
}
else
{
var auctionData = db.Auctions.OrderBy(item => item.EndTime);
}
switch (criteria.GetSortByField())
{
case SearchCriteria.SearchFieldType.Price:
auctionData = auctionData.OrderBy(q => q.CurrentPrice.Value);
break;
case SearchCriteria.SearchFieldType.RemainingTime:
auctionData = auctionData.OrderBy(q => q.EndTime);
break;
case SearchCriteria.SearchFieldType.Keyword:
default:
auctionData = auctionData.OrderBy(q => q.Title);
break;
}
auctionData = SomeMethod();
var viewModel = new SearchViewModel();
return View("Search",viewModel);
}
What is the right way to do something like this.
Well, two options:
Move the declaration to before the if statement, and give it an explicit type:
IQueryable<Auction> auctionData;
if (...)
{
...
}
else
{
...
}
Change the structure to only have a single declaration, e.g. using the conditional operator:
var auctionData = !string.IsNullOrEmpty(criteria.SearchKeyword)
? db.Auctions.Where(q => q.Description.Contains(criteria.SearchKeyword))
: db.Auctions.OrderBy(item => item.EndTime);
Note that I've changed First to Where here - otherwise you would only be matching a single entry, which doesn't sound like much of a search to me, and would make of the rest of the method very odd.
That in itself suggests a third option:
var auctionData = db.Auctions.OrderBy(item => item.EndTime);
var keyword = criteria.SearchKeyword;
if (!string.IsNullOrEmpty(keyword))
{
auctionData = auctionData.Where((q => q.Description.Contains(keyword));
}

Syntax to execute code block inside Linq query?

Here's some code that (obviously) doesn't compile:
var q = from x in myAnonymousTypeCollection
select new {
x.ID,
CalcField = {
switch(x.SomeField) {
case 1:
return Math.Sqrt(x.Field1);
case 2:
return Math.Pow(x.Field2, 2);
default:
return x.Field3;
}
}
};
You get the picture; I'm trying to calculate CalcField in a completely different way, depending on what the value of SomeField is. I can't use a Func<> (or can I?), because the input type is anonymous. So what's the right syntax to get this to work?
First off, I usually prefer the method chain syntax over the query syntax for Linq. With that you can do this easily.
var q = myAnonymousTypeCollection
.Select(x =>
{
object calcField;
switch(x.SomeField)
{
case 1:
calcField = Math.Sqrt(x.Field1);
case 2:
calcField = Math.Pow(x.Field2, 2);
default:
calcField = x.Field3;
return new
{
x.ID,
CalcField = calcField
};
});
Without using method chains, you need either a method or an Func. Let's assume a Func
//replace these with actual types if you can.
Func<dynamic, dynamic> calculateField =
x =>
{
switch(x.SomeField) {
case 1:
return Math.Sqrt(x.Field1);
case 2:
return Math.Pow(x.Field2, 2);
default:
return x.Field3;
}
var q = from x in myAnonymousTypeCollection
select new { x.Id, CalcField = calculateField(x) };
Note: I didn't write this in an IDE, so please excuse any simple errors.
Here is the MSDN for dynamic. However, I have found that once you need to start passing anonymous types around, it is best to make an actual class.
You could wrap your anonymous function as a (self-executing) Func<> delegate. This assumes you know the return type.
var q = from x in myAnonymousTypeCollection
select new {
ID = x.ID,
CalcField = new Func<double>( () => {
switch(x.SomeField) {
case 1:
return Math.Sqrt(x.Field1);
case 2:
return Math.Pow(x.Field2, 2);
default:
return x.Field3;
}
} )()
};
You could quite easily move the switch logic out into another function like so:
private static T GetReturnValue<T>(myClass x)
{
switch (x)
{
case 1:
return Math.Sqrt(x.Field1);
break;
case 2:
return Math.Pow(x.Field2,
2);
break;
default:
return x.Field3;
break;
}
}
And then you just need to pass your object to that function to get back the value you want:
var q = from x in myAnonymousTypeCollection
select new
{
ID = x.ID,
CalcField = GetReturnValue(x)
};

How to use setup of a mocked anonymous type?

I have the following repository:
interface IReportingRepository where T: Report
{
IEnumerable<T> GetReports<T>(object constraints);
}
and I am trying to mock out a call to this repository as:
var reportingRepostory = new Mock<IReportingRepository>();
reportingRepostory.Setup(x =>
x.GetReports<ServiceReport (Moq.It.IsAny<object>())).
Returns(new List<ServiceReport>(){Report1, Report2});
However instead of passing in
Moq.It.IsAny<object>()
I want to pass the anonymous type
new {Activated = true, Enabled = true}
so that I can setup my expectation that the correct anonymous type is used.
You can use custom matchers with a bit of reflection help:
var reportingRepostory = new Mock<IReportingRepository>();
reportingRepostory
.Setup(x => x.GetReports<ServiceReport>(HasProperties()))
.Returns(new List<ServiceReport>(){Report1, Report2});
Where HasProperties method is implemented as follows:
private object HasProperties()
{
return Match.Create(
(object o) =>
{
var properties = o.GetType().GetProperties();
return properties.Any(p => p.Name == "Available")
&& properties.Any(p => p.Name == "Enabled");
});
}
A few implementation bugs that won't be picked up by the original solution:
new {Activated = true, Enabled = false}
new {Activated = true, Enabled = true, Extra = "I'm not meant to be here!"}
new {Activated = true, Enabled = "true"}
Depending on the complexity of your IReportingRepository GetReports method implementations it may be worth considering verifying the anonymous type's property values and value types are as expected and that only exactly the properties expected are present.
var reportingRepostory = new Mock<IReportingRepository>();
reportingRepostory
.Setup(x => x.GetReports<ServiceReport>(IsAnonymousType(new {Activated = true, Enabled = true})))
.Returns(new List<ServiceReport>(){Report1, Report2});
Where the IsAnonymousType method is:
private static object IsAnonymousType(object expected)
{
return Match.Create(
(object actual) =>
{
if (expected == null)
{
if (actual == null)
return true;
else
return false;
}
else if (actual == null)
return false;
var expectedPropertyNames = expected.GetType().GetProperties().Select(x => x.Name);
var expectedPropertyValues = expected.GetType().GetProperties().Select(x => x.GetValue(expected, null));
var actualPropertyNames = actual.GetType().GetProperties().Select(x => x.Name);
var actualPropertyValues = actual.GetType().GetProperties().Select(x => x.GetValue(actual, null));
return expectedPropertyNames.SequenceEqual(actualPropertyNames)
&& expectedPropertyValues.SequenceEqual(actualPropertyValues);
});
}

Can I conditionally create an IEnumerable with LINQ?

I have to following code:
List<Obj> coll = new List<Obj>();
if (cond1) coll.Add(new Obj { /*...*/ });
if (cond2) coll.Add(new Obj { /*...*/ });
if (cond3) coll.Add(new Obj { /*...*/ });
Is there a way to use LINQ or collection initializers for that?
EDIT:
The reason I want to use a collection initializer here is because I have an object tree which I do completely initialize with initialiers and LINQ. This spot is the only one which doesn't follow this principle.
var myobj = new MyBigObj
{
Prop1 = from .. select ..,
Prop2 = from .. select ..,
...
Prop3 = new MySmallerObj
{
PropSmall1 = from .. select ..,
PropSmall2 = from .. select ..,
...
}
};
And now this simply doesn't fit in my scheme:
List<Obj> coll = new List<Obj>();
if (cond1) coll.Add(new Obj { /*...*/ });
if (cond2) coll.Add(new Obj { /*...*/ });
if (cond3) coll.Add(new Obj { /*...*/ });
myobj.Prop4 = coll;
Sure I could put this code in a separate function that returns IEnumerable and call that.. :)
EDIT2:
It looks like I have to code some extension method which I would call like:
new Obj[0]
.ConditionalConcat(cond1, x=>new Obj { /*...*/ })
.ConditionalConcat(cond2, x=>new Obj { /*...*/ })
.ConditionalConcat(cond3, x=>new Obj { /*...*/ })
One fairly horrible option:
var conditions = new[] { cond1, cond2, cond3 };
var values = new[] { new Obj {...}, // First value
new Obj {...}, // Second value
new Obj { ...} // Third value
};
var list = conditions.Zip(values, (condition, value) => new { condition, value })
.Where(pair => pair.condition)
.Select(pair => pair.value)
.ToList();
It's not exactly simpler than the original code though ;) (And also it unconditionally creates all the values - it's only conditionally including them in the collection.)
EDIT: An alternative which only constructs the values when it needs to:
var conditions = new[] { cond1, cond2, cond3 };
var valueProviders = new Func<Obj>[] {
() => new Obj {...}, // First value
() => new Obj {...}, // Second value
() => new Obj { ...} // Third value
};
var list = conditions.Zip(valueProviders,
(condition, provider) => new { condition, provider })
.Where(pair => pair.condition)
.Select(pair => pair.provider())
.ToList();
EDIT: Given your requested syntax, this is a fairly easy option:
new List<Obj>()
.ConditionalConcat(cond1, x=>new Obj { /*...*/ })
.ConditionalConcat(cond2, x=>new Obj { /*...*/ })
.ConditionalConcat(cond3, x=>new Obj { /*...*/ })
with an extension method:
public static List<T> ConditionalConcat<T>(this List<T> source,
bool condition,
Func<T> provider)
{
if (condition)
{
source.Add(provider);
}
return source;
}
If your conditions depend on a single status object (or something that can reduced to),
you can create a method using yield, like the following:
IEnumerable<Obj> GetElemets(MyStatus currentStatus)
{
if(currentStatus.Prop1 == "Foo")
yield return new Obj {...};
if(currentStatus.IsSomething())
yield return new Obj {...};
if(currentStatus.Items.Any())
yield return new Obj {...};
// etc...
yield break;
}
In this way, you will separate the IEnumerable<Obj> generation logic, from the consumer logic.
Old question, but here is another approach using ternery operators ? :, .Concat() and Enumerable.Empty<T>()
var range1 = Enumerable.Range(1,10);
var range2 = Enumerable.Range(100,10);
var range3 = Enumerable.Range(1000,10);
var flag1 = true;
var flag2 = false;
var flag3 = true;
var sumOfCollections = (flag1 ? range1 : Enumerable.Empty<int>())
.Concat(flag2 ? range2 : Enumerable.Empty<int>())
.Concat(flag3 ? range3 : Enumerable.Empty<int>());
Though an old question, but I have an option to solve it in a somewhat clear way and without extensions or any other methods.
Assuming that conditions and initial collection of objects to be created are of same size, I used indexed Where overload approach, so it is not adding objects conditionally, but rather filtering them, with a use of funcs/lambdas we get also laziness, if we want.
The actual creation of objects is not relevant, so I put just boxing of ints (you could replace it with real creation, i.e. getting them from another collection using index), and list manipulation is for getting ints back - but values collection already has 2 elements, so all this could be thrown away (maybe except select with func call in case of using laziness).
Here is the all the code for running sample test right in MSVS
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests
{
[TestClass]
public class Tests
{
[TestMethod]
public void Test()
{
var conds = new[] { true, false, true };
var values = conds.Select((c, i) => new Func<object>(() => i)).Where((f, i) => conds[i]);
var list = values.Select(f => f()).Cast<int>().ToList();
Assert.AreEqual(list.Count, 2);
}
}
}
UPD.
Here also lazy and non-lazy one-liners with "getting object"
var lazy1line = new[] { true, false, true }.Select((c, i) => new Func<object>(() => (DayOfWeek)i)).Where((f, i) => conds[i]).Select(f => f());
var simple1line = new[] { true, false, true }.Select((c, i) => (DayOfWeek)i).Where((f, i) => conds[i]);
Assert.AreEqual(lazy1line.Count(), simple1line.Count());

Categories