In Visual Studio, is there a way to automatically alter source code and add a specific attribute to methods either prior to building or as part of the build process? Similar to code generation except I'm not generating the code, it already exists. Can something like T4 handle this? I don't want to manually add these attributes, I want it to be an automatic, repeatable process.
For example:
public class Test
{
public void MethodOne()
{
}
public void MethodTwo()
{
}
}
Automatically becomes:
public class Test
{
[CustomAttribute]
public void MethodOne()
{
}
[CustomAttribute]
public void MethodTwo()
{
}
}
Background:
I'm using a 3rd party product called Xamarin to build Android + iOS apps using .NET. I'm consuming a SOAP web service using WSDL.exe to automatically generate a proxy. I've added an a custom web service SOAP extension on the client side and the only reliable way I've found of wiring up that custom extension is adding a custom attribute to each web service method generated in the client web service proxy. I have to repeat this process each time I update the web service proxy since it generates fresh code each time.
Couple notes about Xamarin limitations. I don't have access to a web.config or app.config file, which is the normal way of wiring up custom web service SOAP extensions. Xamarin doesn't support web.config or app.config files. I can't use newer technologies like WCF because Xamarin doesn't fully support them (support is still in beta and I've encountered some bugs that prevented me from using them)
I accomplished this using your test class. I'm on Visual Studio 2010, but assume it'll work in 2012.
Open up a Find/Replace window. Switch to the Quick Replace tab. Make sure Use Regular Expressions is checked under Find Options.
Enter this for Find What:
public void Method
Enter this for Replace With:
[CustomAttribute]\n\tpublic void Method
Related
I'm trying to build a COM client which has to instantiate a in-process COM server in C#.
I made two C# projects: one for the client and one for the server. Both projects use x86 target platform and the latter has the option "Register for COM interop" set. I'm using Visual Studio 2013 on a 64bit Windows 7 and compiling with .net 4.
This is the server code:
using System.Runtime.InteropServices;
namespace ComRibbonApplicationMenuServer
{
[ComVisible(true)]
[Guid("CCF43AAC-0822-4C36-90FD-2AFF7B94E71D")]
public interface IComRibbonApplicationMenuServer
{
[DispId(1)]
int OpenWindow();
}
[ComVisible(true)]
[Guid("38B1DE85-BC15-48E1-AFAF-4A7EA506256B")]
[ClassInterface(ClassInterfaceType.None)]
public class ComRibbonApplicationMenuServerClass : IComRibbonApplicationMenuServer
{
public ComRibbonApplicationMenuServerClass()
{
// Needed for COM
}
public int OpenWindow()
{
return 33;
}
}
}
And this is the client:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ComRibbonApplicationMenuClient
{
[Guid("CCF43AAC-0822-4C36-90FD-2AFF7B94E71D")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
interface IComRibbonApplicationMenuServer
{
void OpenWindow();
}
[ComImport, Guid("38B1DE85-BC15-48E1-AFAF-4A7EA506256B")]
class ComRibbonApplicationMenuServerClass
{
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ComRibbonApplicationMenuServerClass comServerClass = new ComRibbonApplicationMenuServerClass();
IComRibbonApplicationMenuServer comServer = (IComRibbonApplicationMenuServer)comServerClass;
comServer.OpenWindow();
}
}
}
The istruction new ComRibbonApplicationMenuServerClass(); throws an InvalidCastException HResult=-2147467262.
What can I do?
Edit:
Thanks Hans for your answer.
If I understand correctly, as I suspected, it is not allowed to create a dotnet COM client for a dotnet COM server without some hacking.
As you have guessed, what I'm trying to do is to test a dotnet program which I've found to work properly when executed as a standalone application, but that crashes (only in Windows XP) when executed by another application via COM.
In order to reproduce the problem I need to build a simple test program that has to start the server and call a method which executes some instructions which, probably, are causing a stack overflow exception. Both programs are using a GUI which maybe part of the problem.
To keep things simple I tried first to make winform program for the COM client, but, reading your anwser, I'm thinking that I have to make a MFC application for testing the COM scenario. What do you think?
throws an InvalidCastException HResult=-2147467262.
You are getting a much more detailed exception message, it will tell you that the cast failed due to the E_NOINTERFACE error return. Which is normally pretty hard to diagnose, except in this case, there really is no interface. The declarations you used in the client are a gross mismatch with the ones used in the server:
the ComRibbonApplicationMenuServerClass declaration in the client doesn't implement any interface. Since you arbitrarily omitted [ClassInterface(ClassInterfaceType.None)], .NET will auto-generate one. It has an random [Guid] that will never match the server's, thus generating the E_NOINTERFACE error.
you arbitrarily gave the client side interface declaration the [InterfaceType(ComInterfaceType.InterfaceIsDual)] attribute. The server omits it and thus uses the default which is ComInterfaceType.InterfaceIsIDispatch. Such an interface can only be called late-bound, the client has to use IDispatch. Which means that if you fix the problem in the first bullet, it will still fail because the server doesn't actually implement the interface. In C#, you'd have to use the dynamic keyword to use such a server.
Clearly it is absolutely essential that the client uses the exact same declarations as the server, normally ensured by using Tlbexp.exe on the server to generate a type library. It is somewhat guessable why you got into this pickle, the IDE will refuse to let you add a reference to the type library, it can see that the server was implemented in .NET and tell you to add a normal .NET reference instead. Which is rather good advice, it doesn't make sense to use COM at all when the normal .NET way already works in a much superior way.
You can fool the machine by using a decompiler on the interop library that Tlbexp.exe generates and copy/paste them into the client, thus making sure you have an exact match. Or by using late-binding with the dynamic keyword in the client app, required anyway because the server uses ComInterfaceType.InterfaceIsIDispatch. Also much less painful since you don't have to repeatedly do the copy/paste step when you alter the server.
But you do need to keep in mind that you are not actually using COM when you do this, the CLR itself is smart enough to see that there's .NET code talking to .NET code and will skip creating the RCW and CCW. So if you are doing this for testing, do keep in mind that you are not actually testing the server the way it is going to be used in a real client app. You might as well test it by actually adding a .NET reference.
I have a Silverlight app I've been working on. This app relies on a custom class called Customer. Instances of this class are returned from my web service. I've need to add a method called CalculateLoyalty() to this class definition. I want CalculateLoyalty to be available on both the server and client-side (my Silverlight app).
Currently, I can use CalculateLoyalty just fine on the server. Unfortunately, the method doesn't seem to get passed across the wire. I have a hunch its some serialization thing. How do I add a method to my class definition on the server-side and ensure that it is available on the client-side?
Thank you!
When you generate a service reference, it only copies public properties and fields. You can share classes between your server and client and avoid using a service reference. I'm not going to go into detail with how to do this, but here are some related questions that explain what needs to be done.
Create WCF Client without auto generated proxy
Call synchronous WCF operation contract methods asynchronously on silverlight
Even if you do this, I have to recommend against putting logic on your DTOs. I'd recommend creating a LoyaltyCalculator class and passing a Customer to this. In fact, you can do this even if you use generate your client through the Add Service Reference option.
Your defult Silverlight solution will have 2 projects.
MyApp - This is your Silverlight project.
MyApp.Web - This is the host web project.
You don't need to do this, but I recommend adding 2 new projects.
MyApp.Shared - A .NET Class Library
MyApp.Shared.Silverlight - A Silverlight Class Library.
At this point, you will want to add a project reference to the appropriate class library to both your Silverlight project and your Web project.
Add class LoyaltyCalculator to MpApp.Shared, or MyApp.Web if you don't want to make the shared libraries. Go ahead and implement this class here.
Now in MyApp.Shared.Silverlight, or MyApp if you don't want to make the shared libraries, select Add -> Existing Item. Browse to and select LoyaltyCalculator.cs. Do Not Double Click It!!! Instead, click the little down / more arrow on the Add button. Now select Add As Link.
LoyaltyCalculator is now available to both your server and client and you only have to maintain one copy.
Methods are not serialized, only data (property/field values) are, so you must be using a different version of the .cs file on the server than you are on the client. Are you sharing the source code between your web service and silverlight projects?
If you are on .NET 4.5/VS2012, you may be able to create a "Portable class library" with your class in it that can be referenced from both your .NET and Silverlight projects.
I'm using a Rally trial account to do an integration proof-of-concept, so I can estimate how much would it cost to integrate our systems with Rally.
I am trying to use the Rally SOAP API with .net, following Rally documentation (/doc/webservice/dotnetsoap.jsp)
I have managed to successfully import Rally Web Services into my c# project, but then Rally documentation says I have to create an object from class RallyServiceService, and although I have a bunch of classes available, this one is not there.
Has anyone else had this problem?
I would appreciate any help.
Thanks
EDIT: (After Jérémie comment)
My code looks like this:
using MyProject.MyNamespace.Rally;
namespace MyProject.MyNamespace {
public class MyClass: MyInterface {
public void MyMethod() {
*RallyServiceService doesn't exist here*
We actually recommend using our REST API rather than SOAP, especially for new development. There is a nice .NET toolkit to help you get started. Docs, code examples and more can be found here:
http://developer.rallydev.com/help/rest-api-net
A resounding +1 to Kyle's recommendation to use Rally's REST API for .NET. Rally's REST API is far more robust, easier to use, and much more performant. If you're just getting started on your integration - you should definitely go with REST :)
However, if you choose to do .NET SOAP, the issue you describe usually results from having added the Rally WSDL as a ServiceReference, instead of adding it as the needed WebReference.
Here's how to add it as a Web Reference:
Open your project in Visual Studio
Right-click on Service Reference -> Add Service Reference
Click Advanced
Click Add Web Reference
Paste in the WSDL URL and click the green arrow
Enter Credentials
Click through mixed-zone security warnings
Name Service as desired
Note presence of Web Reference in Solution Explorer
Observe RallyServiceService in object/method hierarchy
I know EWL has support for services, but I'm not sure what is different about them or what steps I have to take to create one.
Also, is it possible to manually deploy an EWL service in the same manner as a conventional service, or do I have to use the deployment utility?
EWL services give you a simple programming model, with only three places you can put your logic: the Init, CleanUp, and Tick methods. Besides deciding how to divide your logic among these methods, no thinking is required. There is also no flexibility beyond these three methods, so if your problem doesn't neatly fit into this model, don't use an EWL service.
To create an EWL service inside an existing EWL solution:
Add a Windows Service project to your solution. Name it "Windows Service" or anything else. Set it to use the EWL NuGet package, just like the other projects in your solution.
In Library/Configuration/General.xml, add a section like this beneath <WebApplications>:
<WindowsServices>
<Service>
<Name>YOUR-SERVICE-PROJECT-NAME</Name>
<NamespaceAndAssemblyName>YOUR-SERVICE-PROJECT-NAMESPACE</NamespaceAndAssemblyName>
</Service>
</WindowsServices>
Update dependent logic.
Show hidden files in your service project, and add Generated Code/ISU.cs.
Add a Program.cs file to the project, containing this class:
internal partial class Program {
static partial void initGlobalLogic( ref SystemLogic globalLogic ) {
globalLogic = new GlobalLogic();
}
}
Add a CAMEL-CASED-SERVICE-PROJECT-NAME.cs file to the project, containing a class similar to:
internal partial class CAMEL-CASED-SERVICE-PROJECT-NAME {
string WindowsServiceBase.Description { get { return "..."; } }
void WindowsServiceBase.Init() {}
void WindowsServiceBase.CleanUp() {}
void WindowsServiceBase.Tick() {}
}
Remove any boilerplate files in your project that seem unnecessary.
I believe you can install EWL services manually. Just do a build and do whatever you need to with the files in the bin directory.
I'm working with an old windows app in visual studio 2005. A webserviced referenced in the original app has 2 functions and when i peak inside the auto-generated reference.cs file I notice a couple of other functions to allow async calls have been geenrated i.e. BeginWhateverFunctionNameIsCalled and EndWhateverFunctionNameIsCalled.
My problem is that I've created a new windows app and added the same web references but the Begin and End functions are not generated in my reference.cs proxy class. Anyone know whats going on?
It is VS2005, and isn't generating the async methods. OK; is it .NET 2.0 or .NET 3.0 (via the VS2005/WCF add-on)?. It looks like "wsdl.exe" (the original) will generate "FooAsync" methods, but WCF ("scvutil.exe") may generate the "BeginFoo" pattern. You might also look to see if you have used WSE*, for example, "wsewsdl2.exe" or "wsewsdl3.exe".
My bets would be of the WCF version. Note also that different frameworks (Silverlight etc) have their own proxy generation classes.
First step would be to check wsdl file returned by web service if those methods are still available on the server.