I have the following projects:
.Net Standard 2.0 Service Lib
Asp.Net Web API Project
WPF Core 3.1 App
The plan was to share the Service layer between the API and the WPF App.
In the Web API I add a scoped UnitOfWork Service that itself uses scoped DbContexts
services.AddScoped<IUnitOfWork, UnitOfWork>();
The Service Layer uses the UnitOfWork for committing several queries across services (which are added scoped was well) in one transaction. This works as expected.
Service1:
public Service1(IService2 service2,IUnitOfWork unitOfWork)
{
...
}
public async DoSomething()
{
_unitOfWork.DBContext.SomeTable.Add(new SomeTableRecord())
_service2.AddSomeDbRecord(saveInstant:false); //adds a record in another table without saving
await _unitOfWork.SaveAllChanges(); //saves both db changes (inserts) in one transaction
}
Service 2:
public Service2(IUnitOfWork unitOfWork)
{
...
}
public async AddSomeDbRecord(bool saveInstant)
{
_unitOfWork.DBContext.SomeTable2.Add(new SomeTable2Record())
if(saveInstant)
await _unitOfWork.SaveAllChanges(); //saves both db changes (inserts) in one transaction
}
Now when adding my WPF Project where I don't have the Scope of a "WebRequest" anymore, what is a good way to define the scope. Ideally i would like the scope to be around the full chain of calls to a Services method.
I believe this would do what I wanted it to do:
using (var serviceScope = Host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
var service1 = services.GetRequiredService<Service1>();
service1.DoSomething();
}
...but this is obviously not nice or straightforward to write for every call to the service lib and I cannot use ViewModel Constructor Injection for the services.
A scope per ViewModel Instance would be okay too I guess but I don't know how to do this (I'm using MVVM Pattern with a ViewModelLocator)
I would want to stay with Microsoft.Extensions.DependencyInjection as the DI framework as this is also what I'm using in the ASP.Net Project.
Related
I had made a project using ASP.NET Core and React, in this project I made requests in the controller using a command something like this.
const response = await fetch('MyController/GetAll');
and the controller was something like this (simplifying the logic):
using Microsoft.AspNetCore.Mvc;
namespace Crud2.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class MyController : ControllerBase
{
[HttpGet]
public bool GetAll()
{
return true;
}
}
}
The structure of the program was like this before:
Now the structure is like this:
But now I need to adjust for ASP.NET and React, so much so that the structure of the project they passed me has changed, now I can't even call the controller, how can I solve this?
I tried to include the Program.cs file, I tried to create the controller in another solution, I even tried to change the controller name and in all cases the result was none.
I tried to include the Program.cs file, I tried to create the
controller in another solution, I even tried to change the controller
name and in all cases the result was none
Well, as per your description, its evident you are following wrong approach. ASP.NET Core either Web Api or MVC project doesn't work in this way. Hence, if you suddenly include Program.cs and Controller files in other types of project it certaily wouldn't work. To check this, you check weather your MyController running on any server or not.
Why Its not working:
As you might know ASP.NET Core requires a web server along with certain port to run any perticular app same as React app or other SPAs does. For instance, while we run ASP.NET Core app locally, IIS express does the work for us (Server and port stuff), actually Visual studio managed it by itself. So, When you are adding Program.cs and Conterller Class wihtin your Portal Web Project (Not sure what kind of project it is) it certainly missing all necessary configuration files which a standard ASP.NET Core needs. Therefore, you cannot call the controller because, no service is running or port is listenning to your controller.
Correct way:
Before reaching to any particular solution let's have a look how any SPAs(single page application) constructed with asp.net core appliction.
As you may know, we need server/port as well to run or host a client side app. So our project structure should be either following type:
SPA in speperate project
SPA and Asp.net core project integrated within same porject.
Above two structures are pre-requisite for building a SPA with Asp.net core project.
First kind of project runs individually, can you can call directly to any backend service with out any issue becuase two projects are running in different server. No additional configuration is required here.
However, for second type of project structure, we need to configure our SPA project in Program.cs as following:
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "YourSPAName/build";
});
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseSpa(spa =>
{
spa.Options.SourcePath = "YourSPAName";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
Solution:
As per your scenario, you have two choices now, either take completely segregate project and call API the way it generally does.
On the other hand, in case of dual integration, first you have to take Web API project and with this project you should add SPA project in different folder because, React App, it requires, node js server. Thus, you should install all necessary files in that folder. In addition, in Program.cs files you have to tell the compiler how and from where your SPA would be loaded.
In your project, you are adding controller in SPA project which will not work in this way as it requires many additional service and middleware in configuration. So, better approach would be either follow approach 1 or 2.
Note: If you need more infromation, you could check our offical document.
I am running ASP.NET Core 2 application.
I have a local instance of SQL Server where I have a table with a column of type Geometry.
When I go to read this table I get the following errors:
Type Udt is not supported on this platform.
Error parsing column 4 (MyLocation)
However this issue only seems to occur in my API project which calls to a custom made Nuget package that handles the CRUD operations.
If I test the same code in the project that does the CRUD it reads and maps my object.
It is not a connection issue in the API for I can successfully read/write other tables that do not have a Geometry field in it.
What could I possible be missing?
Code:
MyController:
public async Task<IActionResult> Get(Guid Id)
{
var rec = await myRepo.Get<MyData>(id);
// then do stuff
}
*myRepo is injected into my controller.
public class MyData
{
public Guid Id {get;set;}
public IGeometry MyLocation {get;set;}
}
myRepo:
public async Task<TEntity> Get<TEntity>(object id)
where TEntity : class
{
_conn.Open();
return await _conn.GetAsync<TEntity>(id);
}
If this is .NET Core, then I suspect you could have significant issues using sqlgeography etc; UDTs essentially aren't yet implemented in .NET Core:
Additionally, the underlying types that you would want to load use native code; the geo/etc types are not, AFAIK, available in .NET Core.
If I'm wrong, I'm more than happy to try to make whatever changes we need to help make this work, but at the time of writing: I don't think this is going to work through any API (it is not specific to Dapper).
You might want to consider using ASP.NET Core on .NET Framework for today? reference .Net framework 4.5.2 from .Net Core 2.0 project
If this data does actually load from ADO.NET in .NET Core, then I'd be happy to fix whatever I've missed.
I'm trying to write a silverlight app using the await/async 'pattern' (using SL5 and VS11), but I cannot select the 'Generate Task-Based operations' in the service config, is this supposed to be possible (yet)? Can't find much detail on the web (specific to SL)...
I have been able to create manually Task based asynchronous service proxy in Silverlight 5 and Visual Studio 2010.
Works like charm.
I personally prefer to code my contracts and service proxies manually, but if you like to use Generate Service reference you can take a look at this post - WCF + Tasks.
I think it is not supported in Silverlight but you can do that yourself, Maybe a portable class library would be another workaround for this.
public class MyCServiceProxy
{
public static Task<ObservableCollection<MyC>> GetMyCs()
{
var tcs = new TaskCompletionSource<ObservableCollection<MyC>>();
var client = new MyCServiceClient();
client.GetMyCsCompleted += (s,e) => {};
client.GetMyCsAsync();
return tcs.Task;
}
}
The goal here is to be able to step into the WCF service code, as well as the Silverlight app code.
File new project > MvvmLight(SL4)
Add new project > WCF Service app
Add service ref to new service in SL proj
In Model\DataService.cs replace GetData with the code below
public void GetData(Action<DataItem, Exception> callback)
{
// Use this to connect to the actual data service
//var item = new DataItem("Welcome to MVVM Light");
var client = new ServiceReference1.Service1Client();
client.GetDataCompleted += (s, e) =>
{
var userCallback = e.UserState as Action;
var item = new DataItem(e.Result);
userCallback(item, null);
};
client.GetDataAsync(123, callback);
}
Place a breakpoint in the GetData method of Service1.svc.cs
F5 to start debugging.
You’ll get a dialog saying you can’t debug.
“The Silverlight project you are about to debug uses web services. Calls to the web service will fail unless the Silverlight project is hosted in and launched from the same web project that contains the web services.”
What do I need to change to allow me to debug the WCF service?
It sounds like your Silverlight application and WCF Service application are using two different ASP.Net projects within your solution. To debug them in a single solution they'd need to be in the same ASP.Net website.
I have been following some examples of RIA services and although a great concept, i am locked into using a WCF Service (not RIA) as it is also used by other clients like WPF, and asp.net.
THe good thing about RIA was that the ASYNC calling of the service was hidden but with WCF i presume this is not the case so how is it possible to call a WCF Service from silverlight. Add service Reference? and then i presume i have to call and wait for a callback?
Any tutorials on this?
This is a real shame for me as i would have liked to use RIA services.
The other doubt i have that comes to mind is the use of Entity models and data annotations. In ria this was really easy, but if i am using standard wcf services then i presume that the entity classes (actually i am using ENtity framework) will arrive on the client (silverlight) because i do Add Service Reference? Am i correct here?
WIth Data annotations, ria automatically sent the entity classes with the data annotations from the server (ria) to the client (silverlight) - but what is the case with standard WCF services.
So currently i believe that i need a silverlight clietn app and "NO" ria services but i basically would call to wcf services.
The question that arrises now is should i use a mix of RIA and WCF services? silverlight calls RIA and then RIA calls WCF Service...
I would really apprecaite any feedback as i am a little lost of the right direction to take... With ria - it was so simple :-)
Thanks in advance
When you add a service reference to the Silverlight project, the client code will be auto-generated for you, i.e. you will get a class of the form:
public partial class AdventureWorksEntities : global::System.Data.Services.Client.DataServiceContext
From then on, you can use the DataServiceCollection class to in order to hide all the client-server logic under the hood. For example:
using DataServices.EmployeesService;
using System;
using System.Data.Services.Client;
using System.Windows.Controls;
namespace DataServices
{
public partial class MainPage : UserControl
{
private AdventureWorksEntities context = new AdventureWorksEntities(new Uri("Services/EmployeesService.svc", UriKind.Relative));
public MainPage()
{
InitializeComponent();
DataServiceCollection<Employee> data = new DataServiceCollection<Employee>();
this.dataGrid.ItemsSource = data;
data.LoadAsync(context.Employees);
}
}
}
I believe that this Code Project article can get you started.