Magic for Liars is one of those stories where magic exists in a hidden layer of our world, yet it doesn't bring any happiness. People are still people, regardless of their power. And what better way to explore human nature than writing a detective story in a high school for magical kids?
Sarah Gailey writes the story from the viewpoint of the detective, a woman who's greatest frustrations stem from her sister being a magician, while she is just "normal". Yet when she is tasked to find out the circumstances of the death of one of the teachers in the magic school, she jumps on it, making her realize more about herself and the relationships with family and other people.
Yes, the magic is quite incidental and the detective part quite secondary and it could just as well been written in a space academy or science lab or anywhere where flawed people have to manage each other and the balance of power between them. And while I feel the main character was compelling and the story well written, I can't quite shake the feeling I've been duped into reading a touchy-feely type of drama that I didn't really intend to read. You will not read about the specifics of magic in any kind of way; it is quite bluntly used as a tool that the reader needs not understand. You will not be amazed by the amazing feats of deduction of a fascinating detective; the main character is by definition a very normal person with a penchant for introspection and focusing on her own messed up feelings.
In the end you know the spouse did it, or the butler, or the person who flirts with the detective, or the god-like magician, or the weird kid. The culprit isn't even that important for the plot. It's all about the theoretical dynamics between the people and what makes them tick.
Bottom line: a fine investigation into the core motivations of people, woven in a rather short and bland story which purely incidentally features detectives and magic.
The talk is a bit overreaching, doing more things than it should have tried to do, in other words not very efficient, but it contains some really interesting ideas and it's extremely well articulated. As a software developer, I always thrive for efficiency, but what Margaret Heffernan says is that efficiency is good only when the future is predictable. In a fast changing world (and getting faster), efficiency doesn't just not help, it makes things worse. Sometimes you can't plan, but you can prepare.
As expected, I wasn't as interested in the humanistic part of the talk as I was in the technical aspects: algorithmic efficiency is only good with things that can be measured. If you want to innovate or to adapt, it's trial and error that works best. I got that giddiness I get when people tell me "you can't do THAT in software!". Oh, ye of little faith! But there is something there, something extremely useful, a tool that I can use whenever I get stuck in logic loops or some manager tells me that he needs data in order to make a decision about the project that would generate the data.
The problem described here was slightly false. The issue was that IOptionsSnapshot was registered as Scoped and I was just getting the service from the root IServiceProvider. The solution is to call provider.CreateScope() and with that scope as a provider use ActivatorUtilities. Even better, create a scope, then use it to get an instance of a business class that now would support Scoped services as well as Transient, just like a Controller would.
Warning, though: you need to dispose the scope, but you need to make sure you don't use any service that was created there outside the scope (after disposing).
I guess another solution would be to somehow register IOptionsSnapshot<> as transient, but haven't tried it.
And now for the original post
I was trying to create an instance of an object from a service provider to resolve any dependencies, using ActivatorUtilities.CreateInstance<MyObject>(_serviceProvider) and I was getting the exception:
System.InvalidOperationException HResult=0x80131509 Message=Cannot resolve scoped service 'Microsoft.Extensions.Options.IOptionsSnapshot`1[ExternalConfiguration]' from root provider.
My object was receiving a parameter of type IOptionsSnapshot<ExternalConfiguration> and upon further investigation, my service provider (which came as a resolution from the dependency injection for IServiceProvider) was actually a ServiceProviderEngineScope which just refused to resolve any IOptionsSnapshot! Funny enough, if I replaced IOptionsSnapshot with IOptionsMonitor, which in my mind is a heavier interface, it worked without issues. Further still, the problem appeared only inside an IHostedService (a BackgroundService hooked up with services.AddHostedService<T>); if I wrote the same code in a controller action, for instance, it worked fine.
The .NET 2+ implementation of IOptionsSnapshot<T> is OptionsManager<T>. If I manually resolved an instance of OptionsManager before my object, then added it as a parameter, the code worked:
var optionsSnapshot = ActivatorUtilities.CreateInstance<OptionsManager<TestOptions>>(_serviceProvider); var myObject = ActivatorUtilities.CreateInstance<MyObject>(_serviceProvider, optionsSnapshot);
So, specifically, the issue is that in .NET Core, the service provider implementation cannot resolve IOptionsSnapshot interfaces in worker services. You can still do that manually, but I suspect it is a bug, since there is no problem using an IOptionsMonitor instead of IOptionsSnapshot.
A possible solution is to use an additional service provider only for IOptionsSnapshot. Warning, this will not work in a general situation if the dependencies from the additional service provider also need parameters that would be found in the original service provider:
// initialization code var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton( typeof(IOptionsSnapshot<>), typeof(OptionsManager<>) ); serviceCollection.AddSingleton( typeof(IOptionsFactory<>), typeof(OptionsFactory<>) ); _additionalServiceProvider = serviceCollection.BuildServiceProvider();
There are writers like Steven Erikson, describing worlds so vast that characters seem to drown in them, there are writers like William Gibson or Charles Stross, who go so far into the future that people seem to lose their relevance, yet none of them dare to ignore their characters or fail to make them interesting. Yet, that's what Sam J. Miller does in Blackfish City.
10% in and I couldn't bare reading any more of this book. I couldn't care less about the asexual person that is whining about his life, I couldn't care less about the orphan girl whining about her life, I couldn't care less about the sick homosexual boy who is whining about his life and I couldn't care less about the anonymous radio show that narrated what the city was instead of the action showing me. Should I care about all the world getting sunk under the water until the only livable places are floating megacities reminiscent of Waterworld and run by semi abandoned AIs? Should I care about the artificial drama, weird futuristic disease or the grey whining world that Miller describes? No. I refuse!
Bottom line: a poor man's cyberpunk story, with the mechanical "woke", but irrelevant to anything else, sexual and cultural references, with boring characters and a story that I had to make an effort to wade through and still didn't seem to go anywhere.
It takes the third book to see that the "hero's journey" is actually Sigrud's, even if he is the lead character only in this final book of the Divine Cities series. And yes, it is the final book, with a satisfying and very permanent ending, with no hope of dragging it on. Hell, if you consider there are three books and two cities and no gods left, you could wonder how would anyone continue the story if pressured by publishing companies.
Robert Jackson Bennett did not disappoint with City of Miracles, switching registers a little by turning the usual steampunk-noir detective story into more of a chase and revenge thriller. The villain is revealed quite soon, the mystery split into multiple little quirks that nag at you until the end of the book and a massive divine battle to top it all up. Yet I was a little disappointed with the ending. I know, rationally, that it is a great ending, but emotionally I didn't get what I needed from it, especially as I was still fired up on the penultimate chapter only to get an "aftermath" chapter for last.
Maybe it was that one of the options they employed at the end could have easily been the first and solved a lot of problems to boot. Or the fact that a lot of the grief in the final third of the book came from Sigrud not checking his kills, which is something he would never ever do. It felt a little stretched and tired compared to the other stories.
Sometimes I wonder, is it easier or harder for a writer to just abandon a world that he so carefully crafted? Is it a burden that everything that is successful needs to be turned into a trilogy or a series, or is it like coming home, writing about good friends living in your head? Either way, I am kind of grateful to Bennett for ending it all. I would have read more and more books like these if he wrote them, because I am an addict at heart, but I believe both of us can do better.
Bottom line: It's kind of difficult to compare the three books in the series. The first one was the most captivating, but also first, the second one was darker, yet in the same vein, while the last felt philosophical and like the writer wanted to get it done with. You can read either as standalone, although it makes more sense to read the whole trilogy from first to last. I recommend it and I will read more from the author.
Robert Jackson Bennett caught my attention with the first book in the Divine Cities series: City of Stairs. It was a steam-punk and magic detective story featuring a strong female character and her trusty sidekick, with great world building and character work. City of Blades is kind of the same, but slightly darker.
What surprised me in this book was that the author chose to abandon his hero of the previous volume and bring forth one that was a secondary character in that. It's still a whodunit, it's still a strong female lead fighting divine but malevolent forces. If it ain't broke, don't fix it, right? Only City of Blades is more about the personal pain of people, their sacrifice and service, their (dashed) hopes and dreams, the promise of the afterlife.
Long story short, I was planning to read something else at the end of the book, but instead I've just started immediately with City of Miracles, the third and last book in the trilogy. I love this series!
I am going to try something new with this blog post. Usually, when I go somewhere on vacation, the things that capture my attention are not what interest about anybody else in my entourage. I am also not a very lyrical writer, so what's the point of enumerating the places I've been from the perspective (oh, so much used!) of the casual tourist. I imagine myself writing one of those horrid "10 things to do in..." articles, promptly vomit and desist from thinking about it.
With this post, though, I am going to tell you of the wild (but accessible) area that I've explored and where to find it, how I felt and, if I can find the references, what plants and animals live there. You see, when I go somewhere, I avoid people and take really bad pictures of flowers and plants, butterflies, weird things and sometimes landscapes.
The place
I've been to Cheile Bistritei Valcene (the canyon of the river Bistritza from Valcea - there is another one in the north of the country) and in the valley of the Luncavatz river. The vegetation and insects are very similar, so I am going to treat this as a single area, even if their locations are 20 KMs apart:
Cheile Bistritei: from 45.189828, 24.039859 to 45.197871, 24.030284
Raul Luncavat: from 45.186682, 23.917856 to 45.190084, 23.914488
The area is very nice, easy to get to by car, but not very touristic yet, so not a lot of people having picnics and listening loudly to music. Leave your car and walk on the sides of the river(s) and the scenery is verdant and quiet. I have to warn you that even if in Romanian they are called rivers, they are more like creeks, especially at this time of the year. You can even find some caves in the area and if you are the long walk type of person, some 4-5 hour hike routes to more remote areas. Some flowers are white, but the vast majority of them are either yellow-orange or violet in color and probably are much more interesting in ultraviolet than human vision.
Animal life
I haven't seen any animals other than birds, a running lizard and a lot of insects.
I saw several species of butterflies, the most common by far being a medium sized orange with black spots, a fritillary, probably the Silver-washed fritillary (Argynnis Paphia) or mantia imparatului in Romanian. They were frolicking on these tall yellow flowers with large leaves: the yellow oxeye (Telekia speciosa) or brusture and ochiul-boului in Romanian. The next most common was a shy dark butterfly with a crimson edge on its wings. Probably the Woodland ringlet (Erebia Medusa), I have no idea what the Romanian popular name for it is.
Argynnis Paphia on a Telekia speciosa
Erebia Medusa
Some other butterflies: the cabbage white (Pieris rapae) or fluturele de varza in Romania, the peacock (Aglais io) or ochi de paun de zi in Romanian, the swallowtail (Papilio machaon) or coada de rindunica in Romanian and even one glimpse of what I think was a marbled white (Melanargia galathea) or tabla de sah in Romanian.
Pieris Rapae
Aglais Io (during my youth Innachis Io)
Papilio Machaon
Melanargia Galathea
One fascinating specimen looked similar to a peacock butterfly from afar only for it to settle in a triangular black and white shape when it stopped. It must have been a moth! I've identified it as a Jersey tiger moth (Euplagia quadripunctaria) or fluturele urs dungat in Romanian.
Euplagia Quadripunctaria
What I also found fascinating is a tree that had apparently been colonized by ants. A lot of wood dust was on the ground and a lot of activity was inside the trunk. Still, there was another hole in the trunk that was filled with wood dust, but no ant activity. Could it have been some sort of other factor, termites or perhaps a disease, that destroyed the tree trunk's interior and the ants were just opportunists?
[youtube:5ewcsMPzSm4]Ants or termites? New behavior or opportunism?
Plants
Now, plants are easier to photograph, but harder to identify. I've mentioned the oxeye. Then there was the touch-me-not (Impatiens noli-tangere) or slabanog and bradulet in Romanian, which appears to have been used traditionally for its medicinal properties, mostly related to kidney or gynecological issues. The Spreading bellflower (Campanula patula) was there, together with its close relative, the Creeping bellflower (Campanula rapunculoides) - both are called clopotei in Romanian. There was the mountain geranium (Geranium robertianum) or napraznic and priboi and iarba sfintului Robert in Romanian, which appears to have anti-stress, anti-cancer and fertility related purposed in traditional medicine.
Impatiens Noli-tangere
Campanula Patula
Campanula Rapunculoides
Geranium Robertianum
Field mustard was present as well (Brassica rapa). This plant was and is used for a variety of reasons in many cultures. The leaves and roots are rich in oil. In Puglia they use the buds as cimedirape in the making of orecchiette pasta. It is a plant from the cabbage family of plants, probably explaining the presence of the cabbage butterflies.
Brassica Rapa
A very interesting flower has a very weird name: the Viper's bugloss (Echium vulgare) or iarba sarpelui in Romanian. It has blue flowers but the filaments of the stamens are red, contrasting with the petals and giving it a violet color per whole. It has medicinal uses as well, as an antidote for snake bites and for its antibiotic and astringent properties.
Echium Vulgare
Another violet flower, with uses in homeopathic medicine but also in poisonings, is aconite or wolfsbane (Aconitum napellus) or omag in Romanian. It contains powerful alkaloids and at one time it was forbidden to grow this plant anywhere in the Roman Empire on penalty of death. Death from intoxication with the plant can occur in as little as half an hour!
Aconitum Napellus
And since we are talking about a violet flower with medicinal properties, how can we ignore the heal-all (Prunella vulgaris) or busuioc salbatic in Romania. The young leaves and stems can be eaten raw in salads; the plant in whole can be boiled and eaten as a potherb; and the aerial parts of the plant can be powdered and brewed in a cold infusion to make a beverage and it is used as an astringent in folk medicine.
Prunella Vulgaris
Not often, but when it happened it was a whole field of them, I found the Orange mullein (Verbascum phlomoides) or luminarica in Romanian. It is also a medicinal plant, used for the calming, sweat inducing and expectorant effects.
Verbascum Phlomoides
I've seen some daisies in the area and also another flower from the same family: the fleabane (Erigeron annuus) or bunghisor in Romanian. Used in salads as well as against the common cold or stomach aches in folk medicine.
Erigeron Annuus
Last, but not least, the evening-primrose or sundrop (Oenothera biennis) or luminita noptii in Romanian. It started as an American plant, much like the fleabane, but it was brought and naturalized in Europe. It has been used medicinally by the native Americans for all kinds of ailments, as it is an edible plant containing an oil with anti inflammatory properties.
Oenothera Biennis
There were a lot of plants without flowers, but I haven't had the time or patience for them. There was one with huge leaves and I photographed it for identification purposes. It turns out it was either the butterbur (Petasites hybridus) or the burdock (Arctium lappa) both called brusture in Romanian, but different species altogether. It's probably the Arctium, but I can't be sure!
Petasites hybridus or Arctium lappa? A lot of stuff called brusture in Romanian!
Resources
It would have been a lot more difficult for me to write this post if it weren't for sites like:
Pl@ntNet - upload photos of plants and get an instant AI driven identification
... and of course Wikipedia and Google, which will let me find the correct association between a Latin name and the regional names
Even with these great resources, it was obvious that not many people will publish nature related posts in any systematic manner. Even this post, three hours in the making, is a random mess of blurry pictures and random observations.
It wasn't the writing, it is competent, without having any other redeeming quality. It wasn't the story, which is as banal as the book cover and the title, but bearable. It was the main character, a person so ordinary that he freezes whenever he is in danger, loses everything he loves several times from people who threaten him with violence and who for seven chapters, under the guise of thinking like a scientist, attempted in vain to realize what was obvious to the reader from the start. Yeah, OK, how dare he not be a superhero with indomitable courage and magical powers! I accept my part of the responsibility, however I could not for the life of me continue to read Dark Matter past chapter 7.
I am going to go on a limb here, though, and guess that the rest of the book will be just the same: a perfectly ordinary man, thrown into another world, whining about everything and not understanding anything because he clings to his idea of normalcy and refuses to adapt, only to somehow find some strength in the end and reach a partially satisfying ending. It's not really science fiction, it's just one of those "what if you would have made other choices in life" things masquerading as science fiction. I have other things to do that read about the emotional torture of a guy who is just too easily tortured. It's like stealing candy from children. I know the hero's journey starts from a state of pleasant equilibrium then something happens to upend that and the hero must fight to reach another state of equilibrium, but the initial state for this book is a boring guy living with his family and incapable of the basest reasoning skills.
So, yeah, I stopped reading it midway. Sorry, Blake Crouch!
The Invention of Nature is an ode to Alexander von Humboldt, the man who has practically invented our concept of nature, inspired Darwin and Goethe and Bolivar and Jefferson and so many others, created the ideas of ecology, Gaia (although it wouldn't be called that for some time), global connection between volcanic activity. He was among the first to popularize the idea that man's mindless exploitation of nature cannot last and will have dire consequences. The last true polymath, Andrea Wulf calls him, and on paper he seems a god: an avid reader, a great thinker, fluent in many languages, exploring on foot tirelessly until in his seventies, dabbling not only in natural sciences, but also politics, social revolution, physics, drawing, prose and poetry. He had been actively writing and corresponding until well in his eighties. The quintessential 19th century romantic scientist, he was interested in everything and anyone and wrote incessantly. At one time he remained out of money because he was paying for the publication of all his books, being interested in spreading the knowledge, not profit. He was collecting rocks, insects, plants, soil samples, etc. then he would send them to other scientists who were interested, for nothing in return.
His view of nature and the cosmos (term that he coined) permeates the vision of our society even now. So how come so few people know about him? To my shame, that includes me. I vaguely knew the name, but had no idea how grand his influence is. Wulf's explanation is that after the first world war (and I guess the second didn't help, either) an anti-German sentiment spread in Europe and America, leading to burning of books, lynching of German people and an overall erasure of anything Germanic from culture.
Now, half of the book is almost exclusively a Humboldt biography and it is awesome! I was imagining how great it would be if someone were to make a TV series about it (Netflix and National Geographic, I am looking at you!): so many details, so many adventures, so many important people of the age. I think the book would have been more accessible if it would been just that. But then the author also described some other people who were influenced by Humboldt, and while knowing that Darwin venerated the man and did everything he did from the moment he read one of the man's books, the others were less interesting or important.
Even so, the other people cover less than a quarter of the book... the rest is acknowledgements, bibliography, references, etc. Andrea Wulf did a wonderful job researching this and bringing Humboldt to life for me. Even if the ending of the book was not as satisfying as the beginning, it's hard for me to rate this any less than excellent. You need to read this!
I can't decide if Velocity Weapon is brilliant or stupid. What I can say is that I didn't like it. Megan O'Keefe tells a story of three characters: a gunnery sergeant who ejects her pod during a space battle and is picked up by an intelligent spaceship, her brother who is a member of the Prime Protectorate and does everything to find her and a thief on some other planet who stumbles upon a strange lab that changes her entire life.
The writing is competent, nothing inspiring, though, and probably that is why I had difficulty finishing the book. But there are also some features of the story that I didn't like. For example of the three main characters who start the book on equal ground, the thief gets less and less space and, worse, her story never connects to the others. It's like O'Keefe wrote a book and a novella and then merged them into a larger book, even if their only commonality is the same universe. Then there is a part of the story that I got invested in, only to be aborted midway; I can't say more without spoiling the story, but I didn't like that.
The thing that bothered me most, though, is how the plot meanders instead of getting to the point. I used to think that a good story would be less straightforward, but now that I read one that just comes and goes, gives you glimpses of the world, then does nothing with them... it just felt like wasted time. Don't get me wrong, the author builds a world with vast opportunities, a universe of multiple colonized worlds connected by star gates which are controlled by the Primes and their technology originated from an alien artifact. She is just beginning the story. The characters might yet come together, the villains might become clearer, the whole thing felt potentially epic, only one would probably have to read all of the books to understand where O'Keefe is planning to go.
Basically the book is a string of almost random events, driven by forces that are never made clear, then somehow brought together by incredible coincidence, while the characters are barely sketched and hard to relate to, especially the male ones. The world has a lot of potential, but little is built on it so far. It feels like Star Wars, a little: a galaxy far far away where everybody is related or knows each other and everything in a chapter happens on one planet only. And it felt dated, as well.
So I can't decide: is this the start of a wonderful epic universe with immense potential or is it just a stupid space opera book that is not very good? I just didn't like it.
.NET Core comes with its own dependency injection engine, separated in the Microsoft.Extensions.DependencyInjection package, and ASP.Net Core uses it by default. In a very simplistic description, it uses an IServiceCollection to add services to, then it builds an IServiceProvider from that list, an interface which returns an implementation based on a type or null if finding none. Any change in the list of services is not supported. There are situations, though, where you want to add new services. One of them being dynamically resolving new types.
Therefore I set up to create a custom implementation of IServiceProvider that fixes that, using the mechanisms already existing in .NET Core. Note that this is just something I did from frustration, "because I could". Most people choose to replace the entire IServiceProvider with an implementation that uses some other DI container, like StructureMap.
First attempt was proxying a normal ServiceProvider and keeping a reference to the collection. Then I would just change the collection and recreate the service provider. That has two major problems. One is that the previous serviceProvider is not disposed. If you try, you automatically dispose all services already resolved and if you do not, you remain with references to the created services. The second, and more dire, is that recreating the service provider will generate new instances for services, even if registered as singletons. That is not good.
I thought of a solution:
keep a list of service providers, instead of just one
use a custom service collection which will let us know when changes occurred
whenever new services are added, add them to a list of new services
whenever a service is resolved, go through the list of providers
if any provider returns a value, provide it
else if any new service create a new provider from the new services and add it to the list
else return null
when disposing, dispose all providers in the list
This works great except the newly added providers are separate from the existing providers so when you try to resolve a type with a second provider and that type has in its constructor a type that was registered in the first provider, you get nothing.
One solution would be to add all services to the second provider, not only the new ones, but then we get back to the original issue of the singletons, only a bit more subtle:
register type1 as a singleton
get an instance of type1 (1)
build the provider
get an instance of type1 (2)
register type2 which receives a type1 in its constructor
get an instance of type2
now, type1 (1) is the same as type1 (2), because it was resolved by the same provider
type1 is different from type2.type1, though, because that was resolved as a different singleton by the second provider in the list
One solution would be to add all previous services as factories, then. For Itype1, instead of returning typeof(type1), return a factory method that resolves the value with our system. And it works... until it reaches a definition (like IOptions) that was registered as an open generic: services.AddSingleton(typeof(IType3<>),typeof(Type3<>)). In case of open generics, you cannot use a descriptor with a factory, because it returns an object, regardless of the generic type argument used. It would not to do return a Type3<Banana> for a requested type of IType3<int>.
So, final version is this:
keep a list of service providers, instead of just one
keep a dictionary of the last object resolved for a type
use a custom service collection which will let us know when changes occurred
whenever new services are added, add them to a list of new services
whenever a service is resolved, go through the list of providers
if any provider returns a value, return it
if no new services registered return null
create a new provider from all the services like this:
if it's a new registration, use it as is
if it's an open generic definition type:
if singleton, add first all the existing resolutions for types that are defined by it
use the original descriptor afterwards
use a registration that proxies to the advanced resolution mechanism we created
when disposing, dispose all providers in the list
This implementation also has a flaw: if a dependency parameter with a generic type definition descriptor was resolved as a singleton by an additional service provider, then is requested directly and can be resolved by a previous provider, it will return a different instance. Here is the scenario:
the initial provider knows to map I<> to M<>
you add a new singleton mapping from X to Y and Y gets a constructor parameter of type I<Z>
you request an instance of X
the first provider cannot resolve it
the second provider can resolve it, therefore it will also resolve a I<Z> as an M<Z> singleton instance
you request an instance of I<Z>
the first provider can resolve it, therefore it will return a NEW singleton instance of M<Z>
This is an edge case that I don't have the time to solve. So, with the caveat above, here is the final version. Use it like this:
// IAdvancedServiceProvider either injected // or resolved via serviceProvider.GetService<IAdvancedServiceProvider> // or even serviceProvider as IAdvancedServiceProvider advancedServiceProvider.ServiceCollection.AddSingleton...
And this is the source code:
/// <summary> /// Service provider that allows for dynamic adding of new services /// </summary> publicinterface IAdvancedServiceProvider : IServiceProvider { /// <summary> /// Add services to this collection /// </summary> IServiceCollection ServiceCollection { get; } }
/// <summary> /// Service provider that allows for dynamic adding of new services /// </summary> publicclass AdvancedServiceProvider : IAdvancedServiceProvider, IDisposable { private readonly List<ServiceProvider> _serviceProviders; private readonly NotifyChangedServiceCollection _services; private readonly object _servicesLock = new object(); private List<ServiceDescriptor> _newDescriptors; private Dictionary<Type, object> _resolvedObjects;
/// <summary> /// Initializes a new instance of the <see cref="AdvancedServiceProvider"/> class. /// </summary> /// <param name="services">The services.</param> public AdvancedServiceProvider(IServiceCollection services) { // registers itself in the list of services services.AddSingleton<IAdvancedServiceProvider>(this);
_serviceProviders = new List<ServiceProvider>(); _newDescriptors = new List<ServiceDescriptor>(); _resolvedObjects = new Dictionary<Type, object>(); _services = new NotifyChangedServiceCollection(services); _services.ServiceAdded += ServiceAdded; _serviceProviders.Add(services.BuildServiceProvider(true)); }
/// <summary> /// Add services to this collection /// </summary> public IServiceCollection ServiceCollection { get => _services; }
/// <summary> /// Gets the service object of the specified type. /// </summary> /// <param name="serviceType">An object that specifies the type of service object to get.</param> /// <returns>A service object of type serviceType. -or- null if there is no service object of type serviceType.</returns> public object GetService(Type serviceType) { lock (_servicesLock) { // go through the service provider chain and resolve the service var service = GetServiceInternal(serviceType); // if service was not found and we have new registrations if (service == null && _newDescriptors.Count > 0) { // create a new service collection in order to build the next provider in the chain var newCollection = new ServiceCollection(); foreach (var descriptor in _services) { foreach (var descriptorToAdd in GetDerivedServiceDescriptors(descriptor)) { ((IList<ServiceDescriptor>)newCollection).Add(descriptorToAdd); } } var newServiceProvider = newCollection.BuildServiceProvider(true); _serviceProviders.Add(newServiceProvider); _newDescriptors = new List<ServiceDescriptor>(); service = newServiceProvider.GetService(serviceType); } if (service != null) { _resolvedObjects[serviceType] = service; } return service; } }
private IEnumerable<ServiceDescriptor> GetDerivedServiceDescriptors(ServiceDescriptor descriptor) { if (_newDescriptors.Contains(descriptor)) { // if it's a new registration, just add it yieldreturn descriptor; yieldbreak; }
if (!descriptor.ServiceType.IsGenericTypeDefinition) { // for a non open type generic singleton descriptor, register a factory that goes through the service provider yieldreturn ServiceDescriptor.Describe( descriptor.ServiceType, _ => GetServiceInternal(descriptor.ServiceType), descriptor.Lifetime ); yieldbreak; } // if the registered service type for a singleton is an open generic type // we register as factories all the already resolved specific types that fit this definition if (descriptor.Lifetime == ServiceLifetime.Singleton) { foreach (var servType in _resolvedObjects.Keys.Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == descriptor.ServiceType)) {
yieldreturn ServiceDescriptor.Describe( servType, _ => _resolvedObjects[servType], ServiceLifetime.Singleton ); } } // then we add the open type registration for any new types yieldreturn descriptor; }
private object GetServiceInternal(Type serviceType) { foreach (var serviceProvider in _serviceProviders) { var service = serviceProvider.GetService(serviceType); if (service != null) { return service; } } return null; }
/// <summary> /// Dispose the provider and all resolved services /// </summary> publicvoid Dispose() { lock (_servicesLock) { _services.ServiceAdded -= ServiceAdded; foreach (var serviceProvider in _serviceProviders) { try { serviceProvider.Dispose(); } catch { // singleton classes might be disposed twice and throw some exception } } _newDescriptors.Clear(); _resolvedObjects.Clear(); _serviceProviders.Clear(); } }
/// <summary> /// An IServiceCollection implementation that exposes a ServiceAdded event for added service descriptors /// The collection doesn't support removal or inserting of services /// </summary> privateclass NotifyChangedServiceCollection : IServiceCollection { private readonly IServiceCollection _services;
/// <summary> /// Fired when a descriptor is added to the collection /// </summary> publicevent EventHandler<ServiceDescriptor> ServiceAdded;
/// <summary> /// Initializes a new instance of the <see cref="NotifyChangedServiceCollection"/> class. /// </summary> /// <param name="services">The services.</param> public NotifyChangedServiceCollection(IServiceCollection services) { _services = services; }
/// <summary> /// Get the value at index /// Setting is not supported /// </summary> public ServiceDescriptor this[int index] { get => _services[index]; set => thrownew NotSupportedException("Inserting services in collection is not supported"); }
/// <summary> /// Count of services in the collection /// </summary> publicint Count { get => _services.Count; }
/// <summary> /// Obviously not /// </summary> publicbool IsReadOnly { get => false; }
/// <summary> /// Adding a service descriptor will fire the ServiceAdded event /// </summary> /// <param name="item"></param> publicvoid Add(ServiceDescriptor item) { _services.Add(item); ServiceAdded.Invoke(this, item); }
/// <summary> /// Clear the collection is not supported /// </summary> publicvoid Clear() => thrownew NotSupportedException("Removing services from collection is not supported");
/// <summary> /// True is the item exists in the collection /// </summary> publicbool Contains(ServiceDescriptor item) => _services.Contains(item);
/// <summary> /// Copy items to array of service descriptors /// </summary> publicvoid CopyTo(ServiceDescriptor[] array, int arrayIndex) => _services.CopyTo(array, arrayIndex);
/// <summary> /// Enumerator for service descriptors /// </summary> public IEnumerator<ServiceDescriptor> GetEnumerator() => _services.GetEnumerator();
/// <summary> /// Index of item in the list /// </summary> publicint IndexOf(ServiceDescriptor item) => _services.IndexOf(item);
/// <summary> /// Inserting is not supported /// </summary> publicvoid Insert(int index, ServiceDescriptor item) => thrownew NotSupportedException("Inserting services in collection is not supported");
/// <summary> /// Removing items is not supported /// </summary> publicbool Remove(ServiceDescriptor item) => thrownew NotSupportedException("Removing services from collection is not supported");
/// <summary> /// Removing items is not supported /// </summary> publicvoid RemoveAt(int index) => thrownew NotSupportedException("Removing services from collection is not supported");
Stranger than we can Imagine feels like a companion book to the 2002 documentary The Century of the Self. Both are really well done and discuss the brusque changes that define the 20th century and they complement each other in content. I recommend them highly to just about everyone except maybe little children.
John Higgs starts the book comparing history to a landscape and the works describing it as maybe roads. There are well trodden paths on this landscape, but also deep forests where few dare enter. He then promises that his book will try to describe the twentieth century by exploring these dark places, avoided by others. I didn't feel that was completely the case, but certainly it was a novel path to take to explain history: Einstein, Heisenberg, Gödel, Lorenz, Mandelbrot, Freud, Picasso, Dalí, Joyce, Leary, Stravinsky, Crowley, Thatcher, The Rolling Stones, Miyamoto and so on. Its basic premise is that an abrupt change occurred at the beginning of the 20th century, when the general belief in absolutes (which he generically calls omphaloi) was replaced with relativism and individuality.
How would classical empires survive these changes when at their core stands the belief in a supreme leader, representing and supported by a supreme god, who protects and enforces rules that are culturally accepted by everyone? They would not, therefore the world wars that ended them. What absolute pillar of belief would survive general relativity, the uncertainty principle, quantum mechanics, the incompleteness theorems, the id and individualism, impressionism, cubism, modernism, postmodernism and finally, the corporation? None of them. Religion not so much dies as it breaks apart in small fragments that then fade away. Morality shakes under the reign of individual desires and psychopathic legal entities. Social norms, economical behavior, even the foundation of money are wiped out and replaced with the new. Art fractures as well, constantly redefining and contradicting itself and everything else. It is the century where value exists only when seen from certain perspectives and nothing has any intrinsic value.
The book ends with a chapter that heralds the coming of a new age, the 21st century: the Internet and the erosion of the last remaining omphalos: truth. If truth also depends on the observer, if there is no one truth, if science if just a belief like any others, what awaits us in the post-truth era?
Overall it is a very interesting and informative book. More than simply stating facts, it is the unexpected connections between things that bring value to the reader, rather fitting considering the subject. Maybe not going into the depths of dark forests, but certainly exploring their edges and the strange beings that live there. Top marks!
The scenario is this, you are used to .NET Framework projects for which Visual Studio restored NuGet packages in a packages folder in the solution folder and then you switch to .NET Core. No packages folder! You google it and you find that there is a global folder in your user's profile where NuGet will download all of these projects, that .NET Core uses it by default and also that you might change this behavior used on a property in nuget.config. So here are the issues you have take into account:
There are two ways of configuring NuGet packages for your projects: a packages.config file and PackageReference elements in your .csproj file
The name of the property you need to set is different based on the type of configuration: repositoryPath and globalPackagesFolder, respectively
There are two formats for configuring nuget properties: using the add element inside the config element and using the repositoryPath element inside the settings element
The format that worked for me in VS 2017 was the config element
There are two locations for the nuget.config file: in a .nuget folder inside your solution folder and directly in the solution folder (or any of its parent folders)
The location that is accepted by the latest versions of NuGet is directly in the solution folder
Sometimes you need to restart Visual Studio for the change in nuget.config files to considered
The path you specify is relative to the nuget.config file, no matter where it is
A bit of an overkill, but try this as the beginning of your nuget.config file that sits next to the .sln file in your solution:
Deathcaster is the final book in the Shattered Realms series, or at least it should be, since it kills off the villain and has everybody live happily ever after. It's one of the least satisfying endings I've read in a long time.
Cinda Williams Chima started slowly, by creating a complex world of realms, magic and a multitude of characters and factions. She spent two books on that. The third book, Stormcaster, was about introducing a powerful and mysterious villain and yet more characters, realms and factions. Deathcaster pretty much ends it all in an until then unknown place, at a random time, for a completely random reason. Imagine Luke Skywalker walking around, playing with his sword, thinking on how to defeat the Death Star and accidentally bumping into and killing the emperor and Darth Vader both. This is how this book feels, after wading through a zillion people, with their feelings described in detail while any military or political strategy is explained (poorly) in a paragraph or two, through their relationships with other people, through their random interactions that always seem to bring them together for no apparent reason and then split them apart randomly and then the villain basically stumbling and falling on their sword.
There is nothing interesting that actually happens, no moral in any of the stories and the development of the characters is basically just beefing up and aging a few years.
Bottom line: the ending of this book makes the reading of the three previous books and this one feel like a complete waste of time. How do you rate a book that makes all the previous ones unrateable? Cinda, you're a troll!
The Flight of Morpho Girl is a short story set in the Wild Cards universe. If you haven't read the books until now, you won't know who the characters are. Even so, this story is so basic that it feels like "The Unsuccessful Mugging of Batman" or "Murder of Crows v Superman": predictable and stakeless.
That doesn't mean that the authors didn't do a good job, it's just that it is a short that brings nothing to the table other than the introduction of Morpho Girl's (Adesina, the teenager daughter of Amazing Bubbles) post cocoon form: a teenage girl with very tough butterfly wings. For me it's like a collectible item in the Wild Cards set, nothing more.