I'm querying the Google Books API, and I'm parsing the books into a custom object like this:
foreach (JToken item in items)
{
try
{
FoundBookViewModel viewModel = new FoundBookViewModel
{
Title = item.SelectToken("volumeInfo.title").ToString(),
Isbn13 = item.SelectToken("volumeInfo.industryIdentifiers[1].identifier").ToString(),
Authors = item.SelectToken("volumeInfo.authors").Select(x => x.ToString()).ToList().Aggregate((i, j) => i + ", " + j),
Pages = item.SelectToken("volumeInfo.pageCount").ToString(),
ImageUri = item.SelectToken("volumeInfo.imageLinks.smallThumbnail").ToString()
};
newList.Add(viewModel);
}
catch (Exception)
{
newList.Add(new FoundBookViewModel());
}
}
However, sometimes not all data is available. Sometimes there is no 'pageCount', sometimes there is no 'ISBN13', etc. In those cases an exception is thrown at the ToString() part.
So what I want is this: when an exception is thrown for one of the properties, I just want it to be an empty string. But I don't know a clean way to accomplish this.
I tried multiple things:
I wrapped the whole thing inside a try catch, but then I don't know what property was empty, so I can't 'fill' it with an empty string.
I tried using safe casting ('as string') but that operation is not available on SelectToken().
Couple of other things that didn't work anyway.
Of course I could put every operation inside its own try catch, but that will result in 5 try catch blocks in this situation, so that's not what I'm looking for.
Who knows a clean way to solve this? Btw. I choose to use LINQ to JSON instead of materializing it directly because the Google Books API doesn't neatly map to simple entities (the JSON contains lots of nesting).
If you don't want to throw exception - don't...
I.e. you can change item.SelectToken("volumeInfo.pageCount").ToString() into:
item.SelectToken("volumeInfo.pageCount") == null?
String.Empty : item.SelectToken("volumeInfo.pageCount").ToString()
Related
im trying to deploy a simple search function that uses a simple tag system, probably there are better ways to bt this is the solution i landed on:
public async Task<ActionResult<IEnumerable<t_usuarios_pub>>> Gett_usuarios_pubByTag(string tag)
{
string[] TagList;
TagList = tag.Split(',');
List<t_usuarios_pub> results = new List<t_usuarios_pub>();
var pubs = from m in _context.t_usuarios_pub select m;
if (!String.IsNullOrEmpty(tag))
{
foreach (var Itag in TagList)
{
pubs = pubs.Where(s => (s.tag.Contains(Itag) && s.estatus<2)).OrderBy(x => x.estatus);
foreach(var x in pubs)
{
if (!results.Contains(x))
{
results.Add(x);
}
}
}
}
return await results.AsQueryable().ToListAsync();
}
problem is that the List results cant be converted to IQueryable, this is the error stack.
Any idea of how i can properly implement it ?
System.InvalidOperationException:
The source 'IQueryable' doesn't implement 'IAsyncEnumerable<UserPostAPI.Models.t_usuarios_pub>'.
Only sources that implement 'IAsyncEnumerable' can be used for Entity Framework asynchronous operations.
ยดยดยด
Since results is a local variable of List<> type, I don't believe you need to await the last line. It might just work with:
return results.AsQueryable();
In which case, your method may not even need to be an async method. Or, depending on what _context is, perhaps the await needs to be on the pubs filter call:
pubs = await pubs.Where(s => (s.tag.Contains(Itag) && s.estatus<2))
.OrderBy(x => x.estatus)
.ToListAsync();
Furthermore, since your method says it returns an IEnumerable<>, you probably don't need the .AsQueryable(), either:
return result;
There's also a lot of refactoring you could do -- here are just a few things you may want to consider:
Move the String.IsNullOrEmpty(tag) check to the beginning of the method as a guard.
If this is user input, trim the split tags in TagList to avoid any issues with extra whitespace, and then be sure to remove any resulting empty members.
You could put the estatus < 2 check in your query to reduce having to re-check it again for every item in pubs for every ITag.
I have a problem, under http://www.pathofexile.com/api/public-stash-tabs link there is a huge API that returns a JSON string. Many of fields in this JSON are optional, that means they only appear if there is value present.
So theoretical "Item1" can have "abyssJewel" property but
"item2" doesnt have to have "abyssJewel" property
When i try to query this JSON with JSON.Linq like this
AbyssJewel = (bool)item["abyssJewel"];
in the case of Item1 everything is good and it returns proper value
but in case of Item2 i get exception "InvalidOperationException, Cannot access child value on Newtonsoft.Json.Linq.JProperty"
I understand its because for Item2 no abyssJewel property in JSON exists so it throws exception.
My question is this, how can i handle it so that instead of throwing exception it would return a default or null value for this particular field?
I have tried playing with Activator but couldnt make anything working on my own. Any tips?
im instantiating it like this:
apiPages.Add(new Page
{
Next_Change_Id = (string)jsonObject["next_change_id"],
Stashes = jsonObject["stashes"].Select(stash => new Stash
{
AccountName = (string)stash["accountName"],
StashName = (string)stash["stash"],
StashType = (string)stash["stashType"],
Public = (bool)stash["public"],
LastCharacterName = (string)stash["lastCharacterName"],
UniqueId = (string)stash["id"],
Items = stash.Select(item => new Item
{
AbyssJewel = (bool)item["abyssJewel"],
...tl;dr...
Instead of casting directly you should try to use the TryParse() method from the Boolean class, if something goes wrong it must return false. See here
Hope it will fix your problem.
I'm using selenium to automate some data entry tasks for work.
Problem I'm having:
I need to check if a select (dropdown) has an option, and if so select it, otherwise continue.
The select has around 200 options which I didn't think was a lot but it seems to take a long time to go through the list and I'm wondering how I can speed it up.
I'm assuming its related to the type of objects the list is comprised of being beefy? (list of IWebElement)
Tried a basic for loop, as well as using the .Any method on the list, both seem equally unusually slow.
SelectElement brokeragePayeeOfficeSelect = new SelectElement(webDriver.FindElement(By.Id("ContentPlaceHolder1_ddBrokeragePayee")));
IList<IWebElement> officeOptions = brokeragePayeeOfficeSelect.Options;
bool result = officeOptions.Any(o => o.Text == brokerageOfficeArray[i]);
if (result)
{
brokeragePayeeOfficeSelect.SelectByText(brokerageOfficeArray[i]);
}
else
{
Console.WriteLine("Missing:" + brokerageOfficeArray[i]);
continue;
}
The other option is to make the SelectElement.SelectByText method throw its exception faster. Not sure how to do that. Usually takes a minute or so for it to throw.
Ideas?
Your iteration with Any to check if the option is present is rather expensive. Instead try to select the option and catch the exception:
var brokeragePayeeOfficeSelect = new SelectElement(webDriver.FindElement(By.Id("ContentPlaceHolder1_ddBrokeragePayee")));
try {
brokeragePayeeOfficeSelect.SelectByText(brokerageOfficeArray[i]);
} catch (NoSuchElementException) {
Console.WriteLine("Missing:" + brokerageOfficeArray[i]);
continue;
}
I have a query where one property is a path "/Primary/secondary/tertiary/.../.../"
My task is to split this path by the slashes, so every sub-path can be assigned as a property in the query result.
The problem is, that the length varies. Some paths have a post-split array length of 1, some of 7. So I need to have 7 different category columns:
var result = MySource.Where(ms => ...)
.Select(ms => new {
ID = ms.ID,
Name = ms.Name,
Category1 = ms.Path.Split('/')[0],
Category2 = ms.Path.Split('/')[1] //exception
.... //exception
Category7 = ms.Path.Split('/')[6] //exception
});
After the path gets split, the resulting array is of various length (1 - 7) leading into an ArgumentOutOfRangeException. How can I circumvent this exceptions?
I have tried using the nullcoalescence operator ms.Path.Split('/')[1] ?? "N/A", which did not help, because there is no result but an exception thrown. Because of this every shorthand-if statement will fail as well.
Is there a way to catch the exception (wrap in try catch block?) so I can assign a default value if the array is out of bounds?
Your modeling seems a little broken. Instead of a flattened set of properties, populate a single collection. Something like this:
Select(ms => new {
ID = ms.ID,
Name = ms.Name,
Categories = ms.Path.Split('/')
})
Going a step further, you can create an actual (non-anonymous) model to hold this information, encapsulating the logic of category range checking. Something like:
Select(ms => new SomeObject(
ms.ID,
ms.Name,
ms.Path.Split('/')
))
Then in SomeObject you can have all sorts of logic, for example:
In the constructor you can perform input checking on the values, including the count of categories supplied, to ensure the object is valid.
You can keep the collection of categories private and expose properties for 1-7 if you really need to, which internally perform this check. (Though I really don't recommend that. It creates an unnecessary point of change for something that's already handled by a collection, indexing values.) Something like:
public string Category1
{
get
{
if (categories.Length < 1)
return string.Empty;
return categories[0];
}
}
Maybe throw an exception instead of returning an empty string? Maybe do something else? The point is to encapsulate this logic within an object instead of in a LINQ query or in consuming code.
you can do
Category7 = ms.Path.Split('/').ElementAtOrDefault(6) ?? "N/A",
see demo: https://dotnetfiddle.net/4nTBhq
ElementAtOrDefault return the element at index (for example 6, like [6]) but if out of bound return null.
optimized, without calling Split multiple times:
.Select(ms => {
var categories = ms.Path.Split('/');
return new {
ID = ms.ID,
Name = ms.Name,
...
Category7 = categories.ElementAtOrDefault(6),
};
})
What is the proper way to create a variable that will house a list of anonymous objects that are generated through a LINQ query while keeping the variable declaration outside of a try/catch and the assignment being handled inside of a try/catch?
At the moment I'm declaring the variable as IEnumberable<object>, but this causes some issues down the road when I'm trying to use it later...
i.e.
var variableDeclaration;
try{
...
assignment
...
}catch...
EDIT:
If it's relevant (don't think it is) the list of objects is being returned as a Json result from an MVC3 action. I'm trying to reduce the time that some using statements are open with the DB as I'm having some performance issues that I'm trying to clear up a bit. In doing some of my testing I came across this issue and can't seem to find info on it.
EDIT 2:
If I could request the avoidance of focusing on LINQ. While LINQ is used the question is more specific to the scoping issues associated with Anonymous objects. Not the fact that LINQ is used (in this case) to generate them.
Also, a couple of answers have mentioned the use of dynamic while this will compile it doesn't allow for the usages that I'm needing later on the method. If what I'm wanting to do isn't possible then at the moment the answer appears to be to create a new class with the definition that I'm needing and to use that.
It's possible to get around this by creating a generic Cast method as outlined by Jon Skeet here. It will work and give you the intellisense you want. But, at this point, what's wrong with creating a custom type for your linq method?
public class MyClass
{
public int MyInt { get; set; }
}
IEnumerable<MyClass> myClass =
//Some Linq query that returns a collection of MyClass
Well, if you're using LINQ, the query is not evaluated unless materialized...
So, you might be able to:
var myQuery = //blah
try
{
myQuery = myQuery.ToList(); //or other materializing call
}
catch
{
}
Could you perhaps get away with using dynamic ??
dynamic variableDeclaration;
try
{
variableDeclaration = SomeList.Where(This => This == That);
}
catch { }
Not sure what this will affect further in your code block, but just a thought :)
If you are declaring the variable ahead of using it like a try/catch you can't use [var] as it is intendend. Instead you have to type the the variable.
var x = 0;
try{
x = SomethingReturningAnInt();
}
or
int x;
try{
x = SomethingReturningAnInt();
}
However in your case you don't really "know" what the method returns
var x = ...;
try{
x = Something();
}
catch{}
won't work
Option you have when you don't know the type in advance is use of dynamic:
dynamic x;
try{
x = Something();
}
catch{}
(But that feels like going back to VB4)
Another cheat: you can define variable locally (similarly to Jon's hack in Dave Zych answer) and than use it inside try/catch. As long as you can create the same anonymous item type before try-catch you are OK (as anonymous types wit the same field names and types are considered the same):
var myAnonymouslyType = Enumerable.Repeat(
new {Field1 = (int)1, Field2 = (string)"fake"}, 0);
try
{
myAnonymouslyType = ...(item =>
new {Field1 = item.Id, Field2=item.Text})...
}
...
This is safer option than covered in Jon's casting of anonymous types between functions because compiler will immediately find errors if types don't match.
Note: I'd vote for non-anonymous type if you have to go this way...
Note 2: depending on your actual need consider simply returning data from inside try/catch and having second return of default information outside.
This has vexed me for a while. In the end I've build some Generic helper methods where I can pass in the code that generates the anonymous objects, and the catch code as lamdas as follows
public static class TryCatch
{
public static T Expression<T>(Func<T> lamda, Action<Exception> onException)
{
try
{
return lamda();
}
catch(Exception e)
{
onException(e);
return default(T);
}
}
}
//and example
Exception throwexception = null;
var results = TryCatch.Expression(
//TRY
() =>
{
//simulate exception happening sometimes.
if (new Random().Next(3) == 2)
{
throw new Exception("test this");
}
//return an anonymous object
return new { a = 1, b = 2 };
} ,
//CATCH
(e) => { throwexception = e;
//retrow if you wish
//throw e;
}
);
https://gist.github.com/klumsy/6287279