Today I am digging into WCF Data Service and I have a question regarding this. Can I create WCF Data service as Library and just only create WCF data Service in our existing web app and take reference that library using Factory property so service will deploy with existing web application.
As I know We can create WCF Service Library and only need to take reference that library in Web application like :
Create a WCF Library and implement service contract
Create a Web application and add new item as Wcf service file then take reference WCF library
<%# ServiceHost Service="MyServiceLibrary.MyService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" />
Instead of a service library, I want to create OData service library.
Thanks
Yes, you can host a WCF Data Service in your own assembly - with a few little tricks. I researched this a while ago and came up with these steps / instructions.
Here's how:
put your data model (EF Data Model) into its own assembly, let's call it DataModel
create a new class library project (call it MyDataServiceHost)
add a few references:
your DataModel assembly with the data layer
System.ServiceModel
System.ServiceModel.Web
System.Data.Services.Client
System.Data.Services - you cannot pick this from the usual Add Reference dialog under the .NET category - you need to browse for the assembly file. Find the directory C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0 (or C:\Program Files (x86)\... on a 64-bit machine) and pick the System.Data.Services.dll inside it
add a new class to that class library and call it e.g. YourDataService.cs - it will look something like this:
using System.Data.Services;
using System.Data.Services.Common;
using DataModel;
namespace MyDataServiceHost
{
public class YourDataService : DataService<YourModelEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
}
You can name the class anything you like, and it has to derive from DataService<T> where T is the name of your data model; if you're using Entity Framework, it's the name of your object context class - typically something like (database)Entities or whatever you picked when you created the EDM
add another class to your new project, call it MyDataServiceHost.cs and it will look something like this:
using System;
using System.Data.Services;
using DataModel;
namespace MyDataServiceHost
{
public class MyDataServiceHost
{
public static void LaunchDataService(string baseAddress)
{
Uri[] baseAddresses = new Uri[1];
baseAddresses[0] = new Uri(baseAddress);
using(DataServiceHost host = new DataServiceHost(typeof(YourDataService), baseAddresses))
{
host.Open();
Console.WriteLine("DataService up and running.....");
Console.ReadLine();
host.Close();
}
}
}
}
It instantiates a DataServiceHost, which is derived from WebServiceHost (which in turn is derived from ServiceHost) and it will spin up the WCF Data Service runtime for you.
now you can start up your WCF Data Service from any app using:
MyDataServiceHost.LaunchDataService("http://localhost:4444/YourService");
last thing to remember: the app that you use to launch the WCF Data Service must have the connection string (the EDM connection string, if you're using Entity Framework) in its app.config (or web.config) in order for this to work!
Related
I`ve added a service Reference based on a local wsdl file to my .net core 6 application.But the Interface i get from the Reference gives me addidional data types.
If i implement the interface it should give me following method.
public Ack Heartbeat(Heartbeat parameter)
{
(my impl. here)
}
but instead its generating me
public HeartbeatResponse HeartbeatAsync(HeartbeatRequest request)
{
(my impl. here)
}
So for all my methods defined by the interface there is a new datatype with ...Response and ...Request
Ive read that this could have to do something with the setting "always generate message contracts" in the add sercvice reference setings. But i have`nt checked this setting.
I created a ASP.NET 6, Blazor Server-side project. I injected a logger to the WeatherForecastService classes. I created a library project, and referenced it from the ASP.NET project. I created a object in that library in the ASP.NET project and passed a logger.
If I start it in debug mode in Visual Studio, the log messages from both projects are printed in the Output panel. That is good, but what I what I want to do is, in addition to that (that is, not disabling the log output in the Output panel of VS), show the logs within my ASP.NET project. For example, there can be a "Logs" page.
Probably there is no easy way to send log messages to the client browser in real-time, so I am going to poll the server at every second for new log messages. To do that, I think I have to get notified whenever a log message happens in the ASP.NET project. Not just for the logs from the ASP.NET project itself, but from the referenced project, too, just like VS's Output panel. Can I do that?
ASP.NET 6, Blazor Server-side project
namespace BlazorApp1.Data
{
public class WeatherForecastService
{
private readonly ILogger _logger;
public WeatherForecastService(ILogger<WeatherForecastService> logger, IServiceProvider sp)
{
_logger = logger;
var d = new Dog(sp.GetRequiredService<ILogger<Dog>>());
logger.LogInformation("WeatherForecastService created.");
}
}
Referenced "library" project
using Microsoft.Extensions.Logging;
namespace ClassLibrary1
{
public class Dog
{
public Dog(ILogger<Dog> logger)
{
logger.LogInformation("Dog created.");
}
}
}
Depending on where are you logging you are ether pooling the file or the database. For referenced projects and logs in them you need to implement logger and actually log data to the same file. or different one, but in service you need to fetch all data from all the files.
As far as i know default logger that is logging to console is just for that. You need to ether implement your own logging library or you can import serilog or log4net. And insted of using default ILogger in the same way you use your implementation witch logs data to ether file or db.
Microsoft link for implementing logging provider https://learn.microsoft.com/en-us/dotnet/core/extensions/custom-logging-provider
I have created a 'WCFService' application under 'WCFSolution' solution and generated the DBContext using Entity Framework from a Database 'DemoDB' in 'WCFService' application. and also created some CRUD methods in WCFService (Which is working great).
Then I created an empty 'WCFMVCApp' MVC application under the same solution ('WCFSolution') and also added the service reference to this app. Now i needed to create a controller ('HomeController') with the DBContext that is generated in that WCFService, so that i can generate the views based on the WCF models while creating the controller.
I could create a new EF in WCFMVCApp but it would defeat the purpose of WCF. Any way to do this. or is it possible? Any help would be appreciated. Thank you.
If you are using a WCF Service, in your MVCProject you don't have a DbContext to deal with and you should not add a reference to your WCF Service. You have some options.
Solution 1: Use a client
In your MVC Project create a data service client. Your service should be running and you need the data service tools installed. Then you can add a service reference and some proxy classes are generated for you.
WCF Data Services 5.6.0 RTM Tools Installer
Solution 2: Add a DbContext dll
You can have your DbContext living in a seperate class library that you reference in your service and your MVC project.
In both cases you are using DataServiceContext to perform CRUD operations. For the second one you may have to add an an implementation for ResolveType. To get an idea how to do this, this is how the automatic generated DataServiceContext would resolve types:
ODataSamples
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.OData.Client.Design.T4", "2.1.0")]
public Container(global::System.Uri serviceRoot) :
base(serviceRoot, global::Microsoft.OData.Client.ODataProtocolVersion.V4)
{
....
this.ResolveType = new global::System.Func<string, global::System.Type>(this.ResolveTypeFromName);
....
}
/// <summary>
/// Since the namespace configured for this service reference
/// in Visual Studio is different from the one indicated in the
/// server schema, use type-mappers to map between the two.
/// </summary>
protected string ResolveNameFromType(global::System.Type clientType)
{
global::Microsoft.OData.Client.OriginalNameAttribute originalNameAttribute = (global::Microsoft.OData.Client.OriginalNameAttribute)global::System.Linq.Enumerable.SingleOrDefault(global::Microsoft.OData.Client.Utility.GetCustomAttributes(clientType, typeof(global::Microsoft.OData.Client.OriginalNameAttribute), true));
if (clientType.Namespace.Equals("ODataSamples.CustomFormatService", global::System.StringComparison.Ordinal))
{
if (originalNameAttribute != null)
{
return string.Concat("ODataSamples.CustomFormatService.", originalNameAttribute.OriginalName);
}
return string.Concat("ODataSamples.CustomFormatService.", clientType.Name);
}
return null;
}
I'm currently trying to get my head around WCF services for an ASP.NET dev environment, and I believe that I'm doing well save for one thing that has me stumped.
Basically, I've got a WCF service set up (let's take the default, with an added constructor):
public class MyService : IMyService
{
public MyService() { /* blah */ }
public DoWork() { /* blah */ }
}
The IMyService interface defines the DoWork() method as an [OperationContract], as it should.
So I've got this service referenced in another project (let's say a [Unit] Test Project), via Add Service Reference on the VS2010 UI. This creates a reference to a MyServiceClient which exposes my WCF service methods, as it should.
However, when I do this in my test project:
ServiceReference.IMyService service;
service = new ServiceReference.MyServiceClient();
... the MyService() constructor does not get called, basically because I'm instantiating a MyServiceClient, not a MyService per se.
How do I go about getting that constructor called? I'm planning to use that for initialization purposes (perhaps grabbing a layer in a tiered implementation, for example?).
That constructor will be called on the server when you make your request from the client.
Creating a "reference" to a web service (and then using the client classes) is very different to referencing a regular .DLL. All of your service code will run on the server-side, but not until the service is invoked...
The only way for the server-side constructor to be called for each request is to set the InstanceContextMode to PerCall (in the ServiceBehavior attribute).
I have little Silverlight app that needs to make queries to server, is it possible to return objects to silverlight app or how can I communicate with server?
Use a WCF Service. As long as your objects are Serializable, the runtime will encode and decode them for you transparently.
A simple Silverlight-enabled WCF service looks something like this:
using System.ServiceModel;
using System.ServiceModel.Activation;
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class YourService
{
[OperationContract]
public string DoStuff(string arg)
{
return arg + "stuff";
}
}
You can replace "string" with your datatype by creating a [DataContract].
In my opinion it might be best to use web services to ship whatever is needed to your Silverlight application. I suggest that you use the WebClient class in combination with the URI class to obtain the data. Example:
Uri uri = new Uri(//the url of you webservice, UriKind.RelativeOrAbsolute);
Now create an instance of the WebClient class and add a callback to be called when the read from the web service is completed:
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(CallbackMethod);
wc.OpenReadAsync(uri);
When the data is retrieved from the server, the CallbackMethod is called. The method has an EventArgs object that contains a property called result. You can obtain your data using that property.
Silverlight doesnt need ASP at all to function, if you have a database on a seperate server check out WCF, and then get Silverlight to communicate with the WCF service and then the service with the database, if you want something more transparent, then try out WCF RIA services, this allows you to have a middle-tier approach to data access in silverlight