Im working on a sample project where I need to create a GET method that saves the results in memory and not into a database.
Originally I created the dictionary in PersonController; however, that is a problem since it doesn't persist in memory after the GET request. I need to figure out how to only create one instance of NumbersByName and pass it into the Api Controller. Can this be done?
public class PersonController : ApiController
{
private readonly Dictionary<string, List<int>> NumbersByName;
public PersonController(Dictionary<string, List<int>> numbersByName)
{
NumbersByName = numbersByName;
}
[HttpGet]
public IHttpActionResult GetPersonsNumbers(string name)
{
var personsNumbers = NumbersByName[name];
return Ok(personsNumbers);
}
}
Well you can use cache to store the data
Example:
public string[] GetNames()
{
string[] names = null;
if(Cache["names"] == null)
{
names = DB.GetNames();
Cache["names"] = names;
}
else
{
names = Cache["names"];
}
return names;
}
You can apply the same concept in your code. You can take a look at This
Otherwise, you need to investigate using the singleton design pattern, that way you only create one instance.
Related
Another speed bump on my way to trying to use a Dictionary with a WebAPI. I am trying to implement something with MangoDB and this is only my second time so I am not very knowledgeable here. I have set up a connection with the following code.
private readonly IMongoCollection<Dictionary<Guid, Order>> ordersCollection;
public MongoDBRepository(IMongoClient mongoClient)
{
IMongoDatabase database = mongoClient.GetDatabase(databaseName);
ordersCollection = database.GetCollection<Dictionary<Guid, Order>>(collectionName);
}
Now I have implemented a way to save as I have verified it in the VSC MongoDB extension. I used the following code.
public void CreateOrder(Order order)
{
var values = new Dictionary<Guid, Order>
{
{
Guid.NewGuid(), order
}
};
ordersCollection.InsertOne(values);
}
I've now added several Dictionaries to the DB and I want to get them all. The method in the controller I have says:
[HttpGet]
public Dictionary<Guid, API.Models.Order> GetOrders()
{
var data = repository.GetOrders();
return data;
}
The best I can figure then is that I need to implement something along the lines of:
public Dictionary<Guid, Order> GetOrders()
{
return ordersCollection.Find(new BsonDocument()).ToDictionary();
}
I did some searches and found https://mongodb.github.io/mongo-csharp-driver/2.0/apidocs/html/M_MongoDB_Bson_BsonDocument_ToDictionary.htm and I verified I have a using MongoDB.Bson but it doesn't appear. I am assuming it's because of the way I am utylizing orderCollection. I have found other questions on here using other methods but I only have access to InsertOne, InsertMany, Find, ReplaceOne... Any pointers would be appreciated.
I'm trying to achieve maybe something that might be impossible.
We have a big MVC 5 application. I created a small MVC project to simulate and explain what I want to apply into that big MVC project.
I have a controller that has unique Id. In this sample project the unique Id is regenerated for each request. In the MVC project, it is a bit more complex and different. However it's not relevant in the scope of this example.
public class FooController : Controller
{
public string UniqueId = Guid.NewGuid().ToString("N");
public ActionResult Index()
{
var worker = new WorkerA();
worker.DoWork();
return View();
}
}
The FooController creates WorkerA which creates WorkerB which creates WorkerC and so on. The workers are not the same. They don't have the same interface/implementation. To make the example simple I made them look similar.
Here's the Workers:
public class WorkerA
{
public string UniqueId = string.Empty;
public void DoWork()
{
var worker = new WorkerB();
worker.DoWork();
//...
//...
}
}
public class WorkerB
{
public string UniqueId = string.Empty;
public void DoWork()
{
var worker = new WorkerC();
worker.DoWork();
}
}
I want to have inject the property UniqueId into the worker without having to passing it as a parameter.
I want to avoid having to do this:
public WorkerA(string uniqueId)
{
UniqueId = uniqueId;
}
But I need to do the same for all the other workers.
EDIT
Is there a way to acheive that with ninject?
You can achieve what you want using Microsoft.Practices.Unity in the following manner:
public class WorkerA
{
[Dependency]
public string UniqueId { get; set; }
}
public class WorkerB
{
[Dependency]
public string UniqueId { get; set; }
}
And after that :
var container = new UnityContainer();
container.RegisterType<WorkerA>(new InjectionProperty(nameof(WorkerA.UniqueId),"WorkerAValue"));
container.RegisterType<WorkerA>(new InjectionProperty(nameof(WorkerB.UniqueId), "WorkerBValue"));
Later, you can request the instances from the container with the desired properties configured:
var workerA = container.Resolve<WorkerA>();
var workerB = container.Resolve<WorkerB>();
You can do something like:
worker.GetType().GetField("prop")?.SetValue(worker, "guid");
You could create a singleton class to manage the GUID and deliver it to the child classes that way. This way you can still do it in a constructor but not have to pass it as a parameter
public class GUIDManager
{
private static GUIDManager _instance;
private Guid _activeGuid;
public Guid ActiveGuid {
get { return _activeGuid; }
set { _activeGuid = value; }
}
private GUIDManager()
{
if (_activeGuid == null)
_activeGuid = new Guid();
}
public static GUIDManager GetInstance()
{
if(_instance == null)
{
_instance = new GUIDManager();
}
return _instance;
}
}
public class WorkerB
{
public string UniqueId = string.Empty;
public WorkerB()
{
var manager = GUIDManager.GetInstance();
UniqueId = manager.ActiveGuid.ToString();
}
public void DoWork()
{
var worker = new WorkerC();
worker.DoWork();
}
}
From your question i'm not entirely clear about all the workers in the same request getting the same ID or not. If they all should get the same ID then it's simple:
Wrap the ID in a class and use InRequestScope():
public class BrowserTabId
{
public string browserTabId;
public BrowserTabId(string tabId)
{
if(string.IsNullOrEmpty(tabId))
{
throw new NullArgumentException();
}
this.browserTabId = tabId;
}
public string Id { get { return this.browserTabId; } }
}
Bind<BrowserTabId>()
.ToMethod(ctx =>
new BrowserTabId(HttpContext.Items["BrowserTabId"] as string)))
.InRequestScope();
For testability reasons you can also slap on an interface IUniqueRequestId and create the binding for that.
This will result in all workers / objects created during the same request receiveing the same BrowserTabId. If you don't want to use c-tor injection you can use property injection instead. If you don't want to inject the value all the type, then use a When(..) condition to specify when to inject and when not to. Combine this with the null-object pattern to keep ninject from complaining that it can't inject a requested type.
Property Injection
Adapt a worker as follows:
public class WorkerA
{
[Inject]
public BrowserTabId BrowserTabId { get; set; }
....
}
Note, however, for this to work, like normal constructor injection, it is necessary that either the WorkerA is instanciated by ninject or that Ninject is informed about its existence by Ninject.Inject(workerAInstance)
Scoping
Since you mention that the lifetime of the ID in your actual application is somewhat more complicated, I guess you will have to use something different than InRequestScope - maybe roll your own scope (by using InScope(...)). Or Maybe, InCallScope() is as viable alternative. However, without knowing what exactly it is what you need, it's a bit difficult to advise you properly.
I am designing an API wrapper in C# for Asana, a project management solution. During the design process, I ran into a few roadblocks. I am wondering what a good way to design the API wrapper would be.
The Asana API I am integrating with works with REST. The requests return JSON.
There will be 6 data classes (User, Task, Project, etc), each containing a bunch of strings to hold the data returned from the REST requests. My first idea with these classes is to give them each factory Parse() constructors so I can easily pass in json and get a data object in return. I realize I can't extract the static factory methods into an interface.
I will have a REST request class that will manage sending and receiving data from the REST server. It will always return a JSON string.
Finally, I would like a AsanaAPI class that will contain methods to wrap those exposed on the REST server (i.e GetUser, GetAllUsers, GetTask). Every method either returns a specific data class or an array of data classes. Here are the two cases:
public User GetSingleUser(string userID = "me")
{
if(userID == "") throw new ArgumentException("UserID cannot be blank");
string url = string.Format("{0}/{1}{2}", userUrl, userID, "?opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name");
JSONNode root = JSON.Parse(GetResponse(url))["data"];
return User.Parse(root);
}
public List<User> GetAllUsers()
{
List<User> users = new List<User>();
string url = string.Format("{0}{1}", userUrl, "?opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name");
JSONArray root = JSON.Parse(GetResponse(url))["data"].AsArray;
foreach(JSONNode userRoot in root)
{
users.Add(User.Parse(userRoot));
}
return users;
}
Each method will have that same format, but the User type will be replaced with Project, Task, etc. I want to extract the logic in these two methods because there will be many more methods with almost the exact same format.
In summary, the roadblocks I ran into were the fact that
I can't extract the factory constructor method from the data class.
I can't extract the parsing logic from the request methods
Is there something I can do with generics or is there just a better way of designing this project?
So I created a Parsable interface containing only a Parse method. Each data type implements Parsable. I was able to extract the parsing logic using generic types. It isn't the prettiest solution, but it does work.
public User GetSingleUser(string userID = "me")
{
if(userID == "") throw new ArgumentException("UserID cannot be blank");
string url = "{baseUrl}/users/{userID}?{opt_fields}".FormatWith(
new { baseUrl = BASE_URL, userID = userID, opt_fields = "opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name" });
return (User)ParseJson<User>(AsanaRequest.GetResponse(url));
}
public User[] GetAllUsers()
{
string url = "{baseUrl}/users?{opt_fields}".FormatWith(
new { baseUrl = BASE_URL, opt_fields = "opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name" });
return (User[])ParseJsonArray<User>(AsanaRequest.GetResponse(url));
}
public T ParseJson<T>(string json) where T : Parsable, new()
{
JSONNode root = JSON.Parse(json)["data"];
T ret = new T();
ret.Parse(root);
return ret;
}
public T[] ParseJsonArray<T>(string json) where T : Parsable, new()
{
JSONArray root = JSON.Parse(json)["data"].AsArray;
T[] nodes = new T[root.Count];
for(int i = 0; i < root.Count; i++)
{
T newParsable = new T();
newParsable.Parse(root[i]);
nodes[i] = newParsable;
}
return nodes;
}
Good afternoon fellow stackers (or overflowers, whichever you prefer), this is more of a cleanliness and convenience issue than anything else but I can't imagine that I'm the only one who's ever wondered about it so here we go...
I've got a basic OData enabled WCF Data Service class that's using my Entity Framework data context.
[JsonpSupportBehavior]
public class ControlBindingService : DataService<MyDataContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.DataServiceBehavior.AcceptCountRequests = true;
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
}
protected override MyDataContext CreateDataSource()
{
if (HttpContext.Current == null)
throw new InvalidOperationException("The WCF Data Services implementation must be hosted in IIS.");
string username;
if (HttpContext.Current.User.Identity.IsAuthenticated)
username = HttpContext.Current.User.Identity.Name;
else
{
// The request didn't have user identity, attempt to find UserName in the
// request header before returning 401 to the caller.
if (!String.IsNullOrEmpty(HttpContext.Current.Request.Headers["UserName"]))
{
username = HttpContext.Current.Request.Headers["UserName"];
// REVIEW: We should validate user before passing it to the datacontext.
}
else
throw new DataServiceException(401, "Client did not pass required authentication information.");
}
return MyDataContext.GetInstance(username);
}
[WebGet]
public List<DailyKeyPerformanceIndicator> GetResourceKPIs(
int resourceId, string jsonStart, string jsonEnd, int scenarioId)
{
DateTime start = jsonStart.DeserializeJson<DateTime>();
DateTime end = jsonEnd.DeserializeJson<DateTime>();
if (scenarioId < 1)
{
scenarioId = CurrentDataSource.GetScenarios()
.Single(s => s.IsProduction).ScenarioID;
}
return CurrentDataSource.GetDailyResourceKPI(
scenarioId, start, end, resourceId);
}
}
The data context is just a standard (code-first) DbContext implementation with properties exposing the entity sets, etc..
However, we also have methods on there to expose some tables that we wanted to enforce some constraints upon. Specifically (see code below), we want to know what the caller wants to use the data for so we can return only the appropriate results. For example, if the caller wants to get rows from the employees table--they may want to get all rows, or only rows that they have update privileges for.
[Serializable]
public partial class MyDataContext : DbContext
{
static MyDataContext()
{
Database.SetInitializer<MyDataContext>(null);
}
public MyDataContext()
: base("name=MyDBString")
{ }
// Standard table properties...
public DbSet<User> Users
{
get { return this.Set<User>(); }
}
public DbSet<UserSetting> UserSettings
{
get { return this.Set<UserSetting>(); }
}
public DbSet<SettingDefinition> SettingDefinitions
{
get { return this.Set<SettingDefinition>(); }
}
// Restricted table methods...
public DbSet<Client> GetClients(
DatabasePermissions perms = DatabasePermissions.Select)
{
// getPermissibleSet is a method in a helper class that does some
// magical querying and produces a filtered DbSet.
return getPermissibleSet<Client>(perms);
}
public DbSet<Employee> GetEmployees(
DatabasePermissions perms = DatabasePermissions.Select)
{
// getPermissibleSet is a method in a helper class that does some
// magical querying and produces a filtered DbSet.
return getPermissibleSet<Employee>(perms);
}
}
Now to the root of the issue... What I'd like to avoid having to do is writing a [WebGet] for each and every "restricted table method" on my data context. The reason is really nothing more than redundancy--the [WebGet] method would end up being a direct pass-through to the data context.
So in summary, I'd say what I'm basically looking to do is to mark methods from my data context class that WCF will expose in the same way it does for my DbSet properties. Any takers?
Thanks! J
This is an interesting problem. I'm trying to do similar things. This is kind of throwing a dart here but have you tried something like this? You should probably separate the generics out so you don't create a unique context with each type, but it seems like you should be able to get rid of the duplicate code with generics.
[Serializable]
public partial class MyDataContext<T> : DbContext where T : class
{
static MyDataContext()
{
Database.SetInitializer<MyDataContext>(null);
}
public MyDataContext()
: base("name=MyDBString")
{ }
// Standard table properties...
public DbSet<T> SettingDefinitions
{
get { return this.Set<T>(); }
}
// Restricted table methods...
public DbSet<T> GetClients(
DatabasePermissions perms = DatabasePermissions.Select)
{
// getPermissibleSet is a method in a helper class that does some
// magical querying and produces a filtered DbSet.
return getPermissibleSet<T>(perms);
}
}
Before there was "web api", one had to do actions of the type JsonResult GetPersons(..). Now, with web api, one can have List<Person> GetPersons(..).
I thought the whole point of this was to reutilize the actions, that is: call GetPersons from another action (maybe ActionResult GetPersons(..)).
But after many serialization problems I'm figuring out that this is not an option. For example, as simple as if the object has an enum inside, it can't be serializated to json.
So I ended up with many dynamic X(...) returning anonymous types and I cant really reuse many things of my API. Anny suggestions?
A example of a repeated code is the following:
Json:
from a in b select new { ... }
Not json
from a in b
Also, I've read in many forums that is not good to return the EF object itself, and thats exactly what web api motivates (and the existence of [ScriptIgnore])
The question: How do I reuse queries in the API and in the normal controllers?
How do I reuse queries in the API and in the normal controllers?
By not defining the queries in your API or MVC controllers. You can define the queries in a shared assembly, external to the MVC project, and have the controllers call into that layer.
Example:
Externalized
public interface IQuery<TResult> {}
public interface IQueryProcessor
{
TResult Execute<TResult>(IQuery<TResult> query)
}
public class MyQueryObject : IQuery<MyEntity[]>
{
public string QueryParam1 { get; set; }
public int QueryParam2 { get; set; }
}
API Controller
public class MyApiController : ApiController
{
private readonly IQueryProcessor _queryProcessor;
public MyApiController(IQueryProcessor queryProcessor)
{
_queryProcessor = queryProcessor
}
public IEnumerable<MyApiModel> Get
([FromUri] string queryParam1, int queryParam2)
{
var query = new MyQueryObject
{
QueryParam1 = queryParam1,
QueryParam2 = queryParam2,
};
var results = _queryProcessor.Execute(query);
return Mapper.Map<IEnumerable<MyApiModel>>(results);
}
}
MVC Controller
public class MyMvcController : Controller
{
private readonly IQueryProcessor _queryProcessor;
public MyMvcController(IQueryProcessor queryProcessor)
{
_queryProcessor = queryProcessor
}
public ViewResult Index(string queryParam1, int queryParam2)
{
var query = new MyQueryObject
{
QueryParam1 = queryParam1,
QueryParam2 = queryParam2,
};
var results = _queryProcessor.Execute(query);
var models = Mapper.Map<IEnumerable<MyViewModel>>(results);
return View(models);
}
}