I am trying to map xml cda document to Fhir resources using structureMap resource. Here is structureMap resource which I programmed:
StructureMap structureMap = new StructureMap();
StructureMapGroupComponent group = new StructureMapGroupComponent();
StructureMapGroupInputComponent input = new StructureMapGroupInputComponent() ;
List<StructureMapStructureComponent> structureList =new ArrayList<StructureMapStructureComponent>();
StructureMapStructureComponent structure = new StructureMapStructureComponent();
StructureMapStructureComponent structure2 = new StructureMapStructureComponent();
structure.setUrl("C:\\Users\\a_nas\\Desktop\\Master-Arbeit\\Beispieldokumente_2.06.1\\patient.xml");
structure.setMode(StructureMapModelMode.SOURCE);
structure2.setUrl("http://hl7.org/fhir/StructureDefinition/patient");
structure2.setMode(StructureMapModelMode.TARGET);
structureList.add(structure);
structureList.add(structure2);
structureMap.setStructure(structureList);
input.setName("patient");
input.setMode(StructureMapInputMode.SOURCE);
input.setDocumentation("PatientElgaToFhir");
group.addInput(input);
StructureMapGroupRuleComponent rule = new StructureMapGroupRuleComponent() ;
rule.setName("rule1");
StructureMapGroupRuleSourceComponent ruleSource = new StructureMapGroupRuleSourceComponent() ;
List<StructureMapGroupRuleSourceComponent> rulList = new ArrayList<StructureMapGroupRuleSourceComponent>();
ruleSource.setContext("source");
ruleSource.setElement("birthTime");
StructureMapGroupRuleTargetComponent ruleTarget = new StructureMapGroupRuleTargetComponent();
ruleTarget.setContext("target");
ruleTarget.setElement("BirthDate");
ruleTarget.setTransform(StructureMapTransform.COPY);
rule.addSource(ruleSource);
rule.addTarget(ruleTarget);
group.addRule(rule);
structureMap.addGroup(group);
But I can not find any way to link my defined structureMap resource to corresponding FHIR resources. Actually i don't know how to use this structureMap and get a fhir resource.
Could you please help me?
Related
I am a back-end developer who typically develops APIs and and administration panels all under the same project. I primary use Laravel/PHP, however I recently started delving into .NET Core.
In PHP (Laravel), I could tie my API endpoints and webpages to the same controller actions. For example, An API consumer should be able to create a blog post using the API endpoint. Also, the administrator should be able to create a blog post using the web UI, which should follow the same validation logic, etc.
Here is some pseudocode for the create action.
class BlogPostController
{
//Create a new blog post
function create(request)
{
authorizeAction(); //Make sure the current user is authorized to create a blog post
validateFields(request); //Make sure the posted data is valid for a blog post
//Create the blog post
blogPost = new BlogPost(request);
if(request.isAPI)
return json(blogPost); //Return the new blog post as a json string
return view(blogPost); //Return an HTML representation of the blog post (in administration panel)
}
}
In Laravel, since all routes can have different middleware, I could define two routes to the above action eg POST /api/blogpost and POST /blogpost, each with different authentication schemes. (api would authorize via a JWT token, and the web url would auth via a cookie).
I'm having trouble doing something similar in .NET Core since different authentication schemes cannot be applied via separate middleware as of Version 2 (as far as I know).
My solution to this problem would be adding two authentication schemes like so:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); // => remove default claims
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(cfg=>cfg.SlidingExpiration = true)
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
ClockSkew = TimeSpan.Zero
};
});
And then on my controller use:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme + "," + CookieAuthenticationDefaults.AuthenticationScheme)]
This would effectively challenge a JWT token and a cookie and use whichever one it found. This seems a bit messy to me (and a Microsoft employee would agree)
Am I approaching this whole problem wrong? To me it makes sense to keep all of the logic in one controller and just return json or HTML depending on the type of request. I could have a separate controller for the API endpoints and the webpages, but it seems like a lot of duplication of code. The other option would be to ditch the idea completely and just build an API/Single Page Application that consumes the API.
Is this simply bad design, or is there any elegant way of using different authentication schemes based on the route?
As explained in the asp.net core docs you can configure a custom provider for request localization. As stated in the docs:
Suppose you want to let your customers store their language and culture in your databases. You could write a provider to look up these values for the user.
For that the following code snippet is provided in the docs and also in the github sample Localization.StarterWeb:
services.Configure<RequestLocalizationOptions>(options => {
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr")
};
options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
{
// My custom request culture logic
// DbContext needed here <--
return new ProviderCultureResult("en");
}));});
Can anybody explain me how to inject a DbContext to load the user specific language from DB in the above function?
Well, you can't inject it via constructor because you need to instantiate it during ConfigureServices method and the container isn't available at this point.
Instead you can resolve via HttpContext.
public class CustomRequestCultureProvider : RequestCultureProvider
{
// Note we don't inject any dependencies into it, so we can safely
// instantiate in ConfigureServices method
public CustomRequestCultureProvider() { }
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
var dbContext = httpContext.RequestServices
.GetService<AppDbContext>();
}
}
Be aware though that this may be less than optimal, as you'll have calls to database on every request, so maybe it's worth to abstract this further and use an caching strategy depending on what exactly you want to do with the DbContext.
Usually one should avoid database calls in culture providers, filters etc. for performance reasons
Update:
There is a generic version of GetService<T>, but you need to import the namespace via using Microsoft.Extensions.DependencyInjection;.
This is either super straight forward, or its relatively easy to answer. I have the following code in order to set up my OData Routing Conventions:
// OData
var builder = new ODataConventionModelBuilder();
// OData entity sets..
builder.EntitySet<Book>("Books");
builder.EntitySet<Shelf>("Shelves");
// Bound Function..has to be located on the Tables Controller...
builder.Namespace = "BookService";
builder.EntityType<Table>().Collection
.Function("MostRecent")
.Returns<DateTimeOffset>();
builder.Namespace = "ShelfService";
builder.EntityType<Shelf>()
.Action("NearestEmptyShelf");
...But the problem with this is when the application starts, everything is routed against ShelfService rather than the first function being accessible from BookService.MostRecent and ShelfService.NearestEmptyShelf.
I'm sure others have run into this particular problem when creating services (actions/functions) for their OData Controllers. But I'm just after a definitive answer as to whether or not you can have multiple namespaces in the OData Routing Collection?
You are overwriting your namespace of builder.Namespace = "Bookservice"; with builder.Namespace = "ShelfService";.
To utilize two separate namespaces you need two separate instances of new ODataConventionModelBuilder();
The below is for OData V4
// Book OData Endpoint
var book_builder = new ODataConventionModelBuilder();
// Book OData entity sets..
book_builder.EntitySet<Book>("Books");
// Book Bound Function..has to be located on the Tables Controller...
book_builder.Namespace = "BookService";
book_builder.EntityType<Table>().Collection
.Function("MostRecent")
.Returns<DateTimeOffset>();
// Book Config
config.MapODataServiceRoute(
routeName: "OData - Book",
routePrefix: "book",
model: book_builder.GetEdmModel()
);
// Shelf OData Endpoint
var shelf_builder = new ODataConventionModelBuilder();
// Shelf OData Entity Sets
shelf_builder.EntitySet<Shelf>("Shelves");
// Shelf Bound Function..has to be located on the Tables Controller...
shelf_builder.Namespace = "ShelfService";
shelf_builder.EntityType<Shelf>()
.Action("NearestEmptyShelf");
.Returns<whatever you planned on returning>()
//Shelf Config
config.MapODataServiceRoute(
routeName: "OData - Shelf",
routePrefix: "shelf",
model: shelf_builder.GetEdmModel()
);
It has been a while since I've implemented this mechanism, but you may have to overwrite AttributeRoutingConvention to utilize bound functions in multiple namespaces/controllers using the above method. I know I had a hiccup with it at some point and ended up finding a good method on stack overflow for a public class CustomAttributeRoutingConvention : AttributeRoutingConvention that utilized a public static class HttpConfigExt to provide a CustomMapODataServiceRoute to fix the issue.
It's been a while since this was answered, but I got into this problem recently and found an alternate solution so there it goes...
...
builder.Namespace = "Namespace_A"; // This would be the default namespace
...
function = builder.EntityType<EntityA>()
.Collection
.Function("FunctionInNamespace_B")
.ReturnsCollection<EntityB>();
function.Namespace = "Namespace_B";
Absolutely simple and works like a charm.
Is it possible to consume an OData service (implemented using .Net MVC) with Breeze controllers?
I tried adding a Service Reference from a client aplication, but it simply cannot find a service endpoint when I use Breeze controller on the service.
Any help will be appreciated.
Yes, on the server you will need to create a WCF DataService, something like this:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ODataService : DataService<Your_EF_DbContext> {
// Add your Entity Set names here ... for example
config.SetEntitySetAccessRule("Customers", EntitySetRights.All);
config.SetEntitySetAccessRule("Orders", EntitySetRights.All);
config.SetEntitySetAccessRule("Employees", EntitySetRights.All);
// V3 supported in our next release as well.
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
}
Then from the Breeze client you will need to call
breeze.config.initializeAdapterInstance("dataService", "OData");
to initialize Breeze's OData handling. Then you create an EntityManager and connect to your service. Something like this:
var myEntityManager = new breeze.EntityManager("http://localhost:9009/ODataService.svc");
You can now query and save from your data service via the EntityManager.
I would like to display a list of active users on my application's dashboard.
All of my users are employees and access the application through their Active Directory credentials.
I have used UserPrincipal to get the details of the current user, but can this be done for all of the current users?
You can use a PrincipalSearcher and a "query-by-example" principal to do your searching:
// create your domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// define a "query-by-example" principal - here, we search for all "enabled" UserPrincipal
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.IsEnabled = true;
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
// find all matches
foreach(var found in srch.FindAll())
{
// do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
}
}
If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement. Or see the MSDN documentation on the System.DirectoryServices.AccountManagement namespace.