Castle Windsor passes the registered concrete type to Controller's constructors. A typical implementation (no pun intended) is:
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository;
}
I need to pass the ctor a second parameter, if possible, so that I can pass that val on to the Repository constructor (I know: tramp data alert, but I don't know if there's a straightforward way around it:
public DepartmentsController(IDepartmentRepository deptsRepository, int DBInstance)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository(DBInstance);
}
REPOSITORY
public DepartmentRepository(int dbInst)
{
string connStr = string.Format("Phoo{0}Bar", dbInst);
using (var conn = new OleDbConnection(connStr))
{
using (var cmd = conn.CreateCommand())
{
. . .
Is it possible to tweak what Castle Windsor sends to the Controller constructor this way? If so, how?
AND/BUT: For this to be of any value (to me, anyway), I need to be able to get the int val (that will be passed to the Controller) from the URL the client sends. IOW, if the client asks the server for data via:
http://locohost:4242/Platypus/GetAll/1
I need to pass a "1" as the second argument to PlatypusController.
If the user asks the server for data via:
http://locohost:4242/Platypus/GetAll/42
I need to pass a "42" as the second argument to PlatypusController.
etc.
This is what I did to solve my Controller/Repository data context Dilemma:
0) Added a database context argument to the Controller's routing attribute. IOW, this:
[Route("api/HHSUsers/GetAll")]
...got changed to this:
[Route("api/HHSUsers/GetAll/{dbContext=03}")]
1) Passed that database context arg to the Repository. To wit, this:
return _hhsusersrepository.GetAll();
...got changed to this:
return _hhsusersrepository.GetAll(dbContext);
...so that the Controller method is now:
[Route("api/HHSUsers/GetAll/{dbContext=03}")]
public IEnumerable<HHSUsers> GetAllHHSUsersRecords(int dbContext)
{
return _hhsusersrepository.GetAll(dbContext);
}
2) Changed the corresponding method in the Repository interface from:
IEnumerable<HHSUsers> GetAll();
...to this:
IEnumerable<HHSUsers> GetAll(string dbContext);
3) Changed the Repository method from this:
public HHSUsersRepository()
{
// All the data is loaded here in the ctor
}
public IEnumerable<HHSUsers> GetAll()
{
return hhsusers;
}
....to this:
public IEnumerable<HHSUsers> GetAll(string dbContext)
{
LoadHHSUsers(dbContext);
return hhsusers;
}
private void LoadHHSUsers(int dbContext)
{
string connStr = string.Format("Foo{0}Bar", dbContext);
// The same as previously from this point on, except that this:
// using (var conn = new OleDbConnection(#"Foo Bar Phoo Bar etc"...
// becomes:
// using (var conn = new OleDbConnection(connStr))
4) Tack the dbcontext val to the end of the URL when calling the method, so that it is this:
http://localhost:28642/api/HHSUsers/GetAll/42
...instead of this:
http://localhost:28642/api/HHSUsers/GetAll
If the data context to use is "03" I can omit the dbcontext arg from the URL, as 03 is the default value I set when I appended "=03" to the Controller's "dbContext" routing attribute arg.
I know some fancy-pants propeller-heads will find fault with this for some reason (for one reason because of the tramp data going here and there and everywhere like a hobo on steroids), but my response is the same as that of an athlete who is getting trash-talked by an opposing player and yet whose team is winning: just point at the scoreboard. IOW, this works for me, so that's pretty much all I care about. Style points are for runway models and, again, fancy-pants propeller-heads (AKA Star-Bellied Sneeches (as opposed to us plain
cats with the unstarred bellies)); see "The perfect is the enemy of the good."
This simple way has that self-same benefit -- of being (relatively) simple to grok and, thus, modify/refactor as necessary. Inelegant? Sure, but so was Joe Kapp.
Related
I've recently moved from MVC5 over to .NET Core 2.1 (MVC). Can anyone help me with this please.
I have my ApplicationUser and I've extended the model/table to store the user's FirstName.
In the View, I want to be able to output the current user firstname value.
User in the view is a ClaimsPrincipal so I need to go off to the DB to grab the value I need or access UserManager to get it.
Now, I know I can get that in the controller but I don't want to have to create a JQuery call to grab it every time I need it.
What I do want is to be able to access it server side, ideally via a static helper class.
In the MVC5 I'd have a helper to do the job no problem. Something like this for example:
public static string GetCurrentUserFirstName()
{
string _usrRef = HttpContext.Current.User.Identity.GetUserId();
var user = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(_usrRef);
return user.FirstName;
}
However, .NET Core doesn't work that way.
In a controller I could say:
var user = await _userManager.GetUserAsync(User);
string firstName = user.FirstName;
or I could go off to the DB via a call using Dapper w/ my connection string.
I can't inject the UserManager or ConnectionStrings into the helper via the constructor as it is static.
Is there a way to access either of those in this static helper?
It's the little changes that get you the most!
Thanks to #Kirk Larkin - I've found the solution.
I have to admit, it feels a little more convoluted having to pass things around to gain access to them but this is a good, working solution.
The View:
#using Microsoft.AspNetCore.Identity
#using MyApplication.Helpers
#inject UserManager<ApplicationUser> UserManager
<div>
#await MyHelper.GetLoggedInUserFirstName(UserManager, User)
</div>
The MyHelper file:
public static async Task<string> GetLoggedInUserFirstName(UserManager<ApplicationUser> userManager, ClaimsPrincipal user)
{
string output = "";
try
{
var currentUser = await userManager.GetUserAsync(user);
if(currentUser!=null)
{
output = currentUser.FirstName ?? currentUser.Email;
}
}
catch(Exception e) { }
return output;
}
I have the following dependency chain:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
All interfaces above and implementations are registered in a Windsor Castle container. When I use one connection string, everything works fine.
Now we want to support multiple databases, In UserAppServiceImpl.cs, we want to get different IUserRepository (different IUserDatabaseContext) according to userId as below:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
How can I pass the argument connStr to UserDataContextImpl?
Since the connection string is runtime data in your case, it should not be injected directly into the constructor of your components, as explained here. Since however the connection string is contextual data, it would be awkward to pass it along all public methods in your object graph.
Instead, you should hide it behind an abstraction that allows you to retrieve the proper value for the current request. For instance:
public interface ISqlConnectionFactory
{
SqlConnection Open();
}
An implementation of the ISqlConnectionFactory itself could depend on a dependency that allows retrieving the current user id:
public interface IUserContext
{
int UserId { get; }
}
Such connection factory might therefore look like this:
public class SqlConnectionFactory : ISqlConnectionFactory
{
private readonly IUserContext userContext;
private readonly string con1;
private readonly string con2;
public SqlConnectionFactory(IUserContext userContext,
string con1, string con2) {
...
}
public SqlConnection Open() {
var connStr = userContext.UserId % 2 == 0 ? "conn1" : "conn2";
var con = new SqlConnection(connStr);
con.Open();
return con;
}
}
This leaves us with an IUserContext implementation. Such implementation will depend on the type of application we are building. For ASP.NET it might look like this:
public class AspNetUserContext : IUserContext
{
public string UserId => int.Parse(HttpContext.Current.Session["UserId"]);
}
You have to start from the beginning of your dependency resolver and resolve all of your derived dependencies to a "named" resolution.
Github code link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
Example:
I have my IDataContext for MSSQL and another for MySQL.
This example is in Unity, but I am sure Windsor can do this.
container.RegisterType(Of IDataContextAsync, dbEntities)("db", New InjectionConstructor())
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)("UnitOfWork", New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db")))
'Exceptions example
container.RegisterType(Of IRepositoryAsync(Of Exception), Repository(Of Exception))("iExceptionRepository",
New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db"),
New ResolvedParameter(Of IUnitOfWorkAsync)("UnitOfWork")))
sql container
container.RegisterType(Of IDataContextAsync, DataMart)(New HierarchicalLifetimeManager)
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)(New HierarchicalLifetimeManager)
'brands
container.RegisterType(Of IRepositoryAsync(Of Brand), Repository(Of Brand))
controller code:
No changes required at the controller level.
results:
I can now have my MSSQL context do its work and MySQL do its work without any developer having to understand my container configuration. The developer simply consumes the correct service and everything is implemented.
I'm trying to implement a custom marshaller in Grails. Here's the marshaller:
class AdultPlanningMarshaller implements ObjectMarshaller<JSON> {
boolean supports(Object theObject)
{
return theObject instanceof AdultPlanning
}
void marshalObject(Object theObject, JSON theConverter)
{
AdultPlanning adult = (AdultPlanning)theObject
JSONWriter writer = theConverter.getWriter()
writer.object()
writer.key('id').value(adult.id)
...
writer.endObject()
}
}
I'm registering it in bootstrap.groovy and when I run my integration tests, the supports method fires correctly and the marshalObject method is called with the right object and a JSON object.
When I hit the:
writer.object()
call, an exception gets thrown:
org.codehaus.groovy.grails.web.json.JSONException: Misplaced object: expected mode of INIT, OBJECT or ARRAY but was DONE
So it looks like the writer has already done something to completion, but I have no clue what.
There's not a lot of documentation on JSON marshallers and examples are thin on the ground, but I think I've done this right but it sure isn't working. Any hints would be appreciated.
Further work with the debugger seems to indicate that the object marshaller is being called twice, although breakpoints only happen on the 2nd call for some reason. The first time through it seems to work just fine since the JSONWriter that I get via theConverter.getWriter() when the breakpoint DOES work has the JSON of the object correctly marshalled. It's the 2nd call that is blowing up since the object has ALREADY been marshalled and the JSONWriter is no longer in the "init" state. There's nothing obviously available to tell the difference between the two calls, but why it the marshaller being called twice?
As requested, here's the controller. It's the show action that's being triggered:
class PrimaryController extends RestfulController implements AlwaysRenderJsonException {
def springSecurityService
def familyService
static responseFormats = ['json']
PrimaryController() {
/*
* Tell the base class the name of the resource under management.
*/
super(Primary)
}
#Override
protected Primary createResource() {
//def instance = super.createResource()
//TODO: Should be able to run the above line but there is an issue GRAILS-10411 that prevents it.
// Code from parent is below, as soon as the jira is fixed, remove the following lines:
Primary instance = resource.newInstance()
bindData instance, this.getObjectToBind()
//Code from super ends here
def family = familyService.safeGetFamily(params.long('familyId'))
familyService.addAdultToFamily(instance, family) // Add the primary member to the family.
return instance
}
/**
* Deletes a resource for the given id
* #param id The id
*/
#Override
def delete() {
if(handleReadOnly()) {
return
}
Child instance = queryForResource(params.id)
if (instance == null) {
notFound()
return
}
/*
* Because of the multiple belongsTo relationships of events, you have to get rid of all
* the events and make the profiles consistent BEFORE deleting the person instance.
*/
instance.removePerson()
request.withFormat {
'*'{ render status: NO_CONTENT } // NO CONTENT STATUS CODE
}
}
#Override
protected List<Primary> listAllResources(Map params) {
if (params.familyId == null)
{
throw new ESPException("params.familyId may not be null")
}
def user = springSecurityService.loadCurrentUser()
return \
AdultPlanning.where {
family.id == params.familyId \
&& family.user == user \
&& typeOfPerson == PeopleTypeEnum.PRIMARY
}.list()
}
#Override
protected Primary queryForResource(Serializable id) {
def inst = familyService.safeGetAdult(Long.parseLong(id), params.long('familyId'))
/*
* It was safe to access the requested id, but the requested id may NOT be a primary
* so we need to check.
*/
return (inst instanceof Primary ? inst : null)
}
/**
* Show the primary for the specified family.
*
* #return
*/
#Override
def show() {
Primary primary = familyService.safeGetFamily(params.long('familyId'))?.primary
respond primary
}
}
And the Integration test that triggers it:
void "We should be able to show a primary."() {
given:
family.addToAdults(new Primary(firstName: "Barney"))
family.save()
family.adults.each { it.save() }
when:
controller.response.reset()
resetParameters(controller.params, [familyId: family.id])
controller.request.method = 'GET'
controller.show()
then:
1 * mSpringSecurityService.loadCurrentUser() >> user
controller.response.json
controller.response.json.firstName == "Barney"
}
Well, this is embarrassing.
I use IntelliJ as my Java/Groovy IDE. I had a work related thing to do this morning and quit IntelliJ. When I restarted IntelliJ, the problem described above that had been completely reproducible was no longer happening and the appropriate JSON was being produced under all circumstances.
So it appears that the IntelliJ state somehow got corrupted and the restart cleared it out.
Problem solved.
I guess.
Thanks for the help/suggestions.
As OP mentioned, this error can be triggered because of IntelliJ :
org.codehaus.groovy.grails.web.json.JSONException: Misplaced object: expected mode of INIT, OBJECT or ARRAY but was DONE
Indeed, when debugging the marshaller (for example), IntelliJ displays the "toString()" of the variable, which causes the change of the mode from INIT to DONE.
You may want to remove your breakpoints when facing this issue ;)
The only reason for this can be that where you have started writer.object() for some nested object or array response but missed to write writer.endObject() or you have wrote it two times.
So double check your custom marshaller for all write object.
Reference: https://github.com/grails/grails-core/blob/65b42b66821b32d4efb3a229da99691a00575d60/grails-web-common/src/main/groovy/org/grails/web/json/JSONWriter.java#L258
Hope This helps!
Thanks,
SA
I want to create a JSON file for use as part of a simple web prototyping exercise. LinqPAD is perfect for accessing the data from my DB in just the shape I need, however I cannot get it out as JSON very easily.
I don't really care what the schema is, because I can adapt my JavaScript to work with whatever is returned.
Is this possible?
A more fluent solution is to add the following methods to the "My Extensions" File in Linqpad:
public static String DumpJson<T>(this T obj)
{
return
obj
.ToJson()
.Dump();
}
public static String ToJson<T>(this T obj)
{
return
new System.Web.Script.Serialization.JavaScriptSerializer()
.Serialize(obj);
}
Then you can use them like this in any query you like:
Enumerable.Range(1, 10)
.Select(i =>
new
{
Index = i,
IndexTimesTen = i * 10,
})
.DumpJson();
I added "ToJson" separately so it can be used in with "Expessions".
This is not directly supported, and I have opened a feature request here. Vote for it if you would also find this useful.
A workaround for now is to do the following:
Set the language to C# Statement(s)
Add an assembly reference (press F4) to System.Web.Extensions.dll
In the same dialog, add a namespace import to System.Web.Script.Serialization
Use code like the following to dump out your query as JSON
new JavaScriptSerializer().Serialize(query).Dump();
There's a solution with Json.NET since it does indented formatting, and renders Json dates properly. Add Json.NET from NuGet, and refer to Newtonsoft.Json.dll to your “My Extensions” query and as well the following code :
public static object DumpJson(this object value, string description = null)
{
return GetJson(value).Dump(description);
}
private static object GetJson(object value)
{
object dump = value;
var strValue = value as string;
if (strValue != null)
{
var obj = JsonConvert.DeserializeObject(strValue);
dump = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented);
}
else
{
dump = JsonConvert.SerializeObject(value, Newtonsoft.Json.Formatting.Indented);
}
return dump;
}
Use .DumpJson() as .Dump() to render the result. It's possible to override more .DumpJson() with different signatures if necessary.
As of version 4.47, LINQPad has the ability to export JSON built in. Combined with the new lprun.exe utility, it can also satisfy your needs.
http://www.linqpad.net/lprun.aspx
I want to have a collection of objects, which will be of a class I created called Server. A Server has a string property which is it's IP address, as well as many other pieces of data and objects.
I will have methods for adding and removing servers to this collection, and there will be a need to find a server by it's IP address occasionally. If I were doing this in C# I would use a Dictionary< where the IP string would be the key and the Server object would be the value. I could easily check to see if an item exists in the Dictionary before attempting to add it.
So my requirements are:
1. Ability to add items to the collection (I don't care where they go, front, back, middle)
2. Ability to remove items from anywhere in the collection.
3. Ability to determine if a particular IP address already exists in the collection.
4. Ability to get a reference to a Server object by it's IP.
Edit: Oh yes, I would like it to be strongly typed like the Vector... I guess it's not absolutely necesary, but would be nice.
So it seems like an associative arrays will give me what I need, except I'm not sure about how to do #3 or #4.
public var Servers:Object = new Object( );
public function AddServer(server:Server):void
{
//TODO:need to check if it exists first and throw an error if so
//(it's the caller's responsibility to call DoesServerExist first)
Servers[server.IP] = server;
}
public function RemoveServer(IP:string):void
{
//is it OK to attempt to delete an item if it doesn't already exist?
//do I need to check if it exists before doing delete?
delete Servers[IP];
}
public function DoesServerExist(IP:string):bool
{
//Do I loop through all the elements testing it's IP property?
//Or can I just do something like this?
if(Servers[IP] == null)
{
return false;
}
else
{
return true;
}
}
public function GetServer(IP:string):Server
{
return Servers[IP];//what is returned if this IP doesn't exist?
}
Call me goofy, but why not use the Dictionary class? That gets you everything except strong typing.
If you want strong typing then I'd say you need a custom container, which wraps up a Vector of Servers, and a Dictionary or associative array of IP strings that indexes into the Vector. Then you'd need to expose methods for access, test, insert and remove.
You can just use an array. Example:
var dict:Array = [];
var ip = "164.157.012.122"
dict[ip] = "Server name"
if (dict[ip] == "Server name"){
trace("Yay");
}
//membership
if (dict[ip]){
trace(ip + " is a member of dict");
} else {
trace (ip + " is not a member");
}
//removal:
dict[ip] = null;
AS3 does not really have a built in Dictionary class, unfortunately.