ScopeRegistrationDemo.vala 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using Inversion;
  2. /**
  3. * Example demonstrating scope-local registrations.
  4. *
  5. * This shows how to register items directly on a scope,
  6. * which is useful for per-request context in web applications.
  7. */
  8. public class RequestContext : Object, IRequestContext {
  9. public string request_id { get; set; }
  10. public string path { get; set; }
  11. public RequestContext(string request_id, string path) {
  12. this.request_id = request_id;
  13. this.path = path;
  14. }
  15. }
  16. public interface IRequestContext : Object {
  17. public abstract string request_id { get; set; }
  18. public abstract string path { get; set; }
  19. }
  20. public class RequestLogger : Object {
  21. private RequestContext _context;
  22. public RequestLogger(RequestContext context) {
  23. this._context = context;
  24. }
  25. public void log(string message) {
  26. stdout.printf("[%s] %s\n", this._context.request_id, message);
  27. }
  28. }
  29. public class RequestHandler : Object {
  30. private RequestContext _context;
  31. private RequestLogger _logger;
  32. public RequestHandler(RequestContext context, RequestLogger logger) {
  33. this._context = context;
  34. this._logger = logger;
  35. }
  36. public void handle() {
  37. this._logger.log(@"Handling request for path: $(this._context.path)");
  38. this._logger.log("Request completed successfully");
  39. }
  40. }
  41. public class ApplicationService : Object {
  42. public void do_something() {
  43. stdout.printf("ApplicationService doing something...\n");
  44. }
  45. }
  46. void main() {
  47. // Create the main container with application-wide services
  48. var container = new Container();
  49. // Register application-wide singleton service
  50. container.register_singleton<ApplicationService>((scope) => {
  51. return new ApplicationService();
  52. });
  53. // Register handler as transient - it will receive scope-local dependencies
  54. container.register_transient<RequestHandler>((scope) => {
  55. var context = scope.resolve<RequestContext>();
  56. var logger = scope.resolve<RequestLogger>();
  57. return new RequestHandler(context, logger);
  58. });
  59. // Register logger as transient - it will receive scope-local context
  60. container.register_transient<RequestLogger>((scope) => {
  61. var context = scope.resolve<RequestContext>();
  62. return new RequestLogger(context);
  63. });
  64. stdout.printf("=== Simulating Web Request 1 ===\n\n");
  65. // Create a scope for the first request
  66. var scope1 = container.create_scope();
  67. // Register request-specific context in the scope using register_local_scoped
  68. var context1 = new RequestContext("req-001", "/api/users");
  69. scope1.register_local_scoped<RequestContext>((s) => context1);
  70. // Resolve and use the handler - it gets the request-specific context
  71. var handler1 = scope1.resolve<RequestHandler>();
  72. handler1.handle();
  73. // Also resolve the application service - comes from container
  74. var app_service1 = scope1.resolve<ApplicationService>();
  75. app_service1.do_something();
  76. stdout.printf("\n=== Simulating Web Request 2 ===\n\n");
  77. // Create a separate scope for the second request
  78. var scope2 = container.create_scope();
  79. // Register a different context for this request
  80. var context2 = new RequestContext("req-002", "/api/products");
  81. scope2.register_local_scoped<RequestContext>((s) => context2);
  82. // This handler gets the second request's context
  83. var handler2 = scope2.resolve<RequestHandler>();
  84. handler2.handle();
  85. stdout.printf("\n=== Demonstrating Fluent API with as_type ===\n\n");
  86. // Create a scope with an instance registered against an interface
  87. var scope3 = container.create_scope();
  88. var context3 = new RequestContext("req-003", "/api/fluent");
  89. // Use fluent API to register against multiple types
  90. scope3.register_local_scoped<RequestContext>((s) => context3)
  91. .as_type(typeof(IRequestContext)); // Also register as interface
  92. // Can now resolve by either the concrete type or interface
  93. var by_concrete = scope3.resolve<RequestContext>();
  94. var by_interface = scope3.resolve<IRequestContext>();
  95. stdout.printf("Resolved by concrete type: %s\n", by_concrete.request_id);
  96. stdout.printf("Resolved by interface: %s\n", by_interface.request_id);
  97. // Verify they're the same underlying object
  98. stdout.printf("Same instance: %s\n", ((Object)by_concrete) == ((Object)by_interface) ? "yes" : "no");
  99. stdout.printf("\n=== Demonstrating Scope Isolation ===\n\n");
  100. // Create a new scope - it does NOT inherit the other scope's local registrations
  101. var isolated_scope = container.create_scope();
  102. // This would throw because RequestContext is not registered in isolated scope
  103. try {
  104. var handler_isolated = isolated_scope.resolve<RequestHandler>();
  105. } catch (Error e) {
  106. stdout.printf("Expected error in isolated scope: %s\n", e.message);
  107. }
  108. stdout.printf("\n=== Demonstrating resolve_all with Both Sources ===\n\n");
  109. // Register an additional RequestContext in scope2 using transient
  110. scope2.register_local_transient<RequestContext>((s) => {
  111. return new RequestContext("req-002-secondary", "/api/products/secondary");
  112. });
  113. // resolve_all returns both scope-local and container registrations
  114. var all_contexts = scope2.resolve_all<RequestContext>();
  115. stdout.printf("All RequestContext instances:\n");
  116. foreach (var obj in all_contexts.to_immutable_buffer()) {
  117. if (obj != null) {
  118. var ctx = (RequestContext) obj;
  119. stdout.printf(" - %s: %s\n", ctx.request_id, ctx.path);
  120. }
  121. }
  122. stdout.printf("\n=== Scope-Local Scoped Factory Demo ===\n\n");
  123. var scope4 = container.create_scope();
  124. // Register a scoped factory - same instance returned within the scope
  125. scope4.register_local_scoped<RequestContext>((s) => {
  126. stdout.printf("Creating scoped RequestContext...\n");
  127. return new RequestContext("req-004", "/api/scoped");
  128. });
  129. // First resolution creates the instance
  130. var ctx4a = scope4.resolve<RequestContext>();
  131. stdout.printf("First resolution: %s\n", ctx4a.request_id);
  132. // Second resolution returns the cached instance
  133. var ctx4b = scope4.resolve<RequestContext>();
  134. stdout.printf("Second resolution: %s\n", ctx4b.request_id);
  135. // Verify they're the same instance
  136. stdout.printf("Same instance: %s\n", ctx4a == ctx4b ? "yes" : "no");
  137. stdout.printf("\nDone!\n");
  138. }